diff --git a/stdlib/Makefile b/stdlib/Makefile
index 370cfa57aa..178151a64f 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -281,6 +281,7 @@ tests := \
tst-getenv-thread \
tst-getenv-unsetenv \
tst-getrandom \
+ tst-getrandom-errno \
tst-getrandom2 \
tst-labs \
tst-limits \
diff --git a/stdlib/tst-getrandom-errno.c b/stdlib/tst-getrandom-errno.c
new file mode 100644
index 0000000000..75a60e53ad
--- /dev/null
+++ b/stdlib/tst-getrandom-errno.c
@@ -0,0 +1,37 @@
+/* Test errno handling in getrandom (bug 32440).
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+
+static
+int do_test (void)
+{
+ errno = -1181968554; /* Just a random value. */
+ char buf[4];
+ int ret = getrandom (buf, sizeof (buf), -1); /* All flags set. */
+ if (errno != ENOSYS)
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (ret, -1);
+
+ return 0;
+}
+
+#include
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
index c8c578263d..0dc8fa6e65 100644
--- a/sysdeps/unix/sysv/linux/getrandom.c
+++ b/sysdeps/unix/sysv/linux/getrandom.c
@@ -20,6 +20,8 @@
#include
#include
#include
+#include
+#include
static inline ssize_t
getrandom_syscall (void *buffer, size_t length, unsigned int flags,
@@ -201,11 +203,12 @@ getrandom_vdso (void *buffer, size_t length, unsigned int flags, bool cancel)
cancellation bridge (__syscall_cancel_arch), use GRND_NONBLOCK so there
is no potential unbounded blocking in the kernel. It should be a rare
situation, only at system startup when RNG is not initialized. */
- ssize_t ret = GLRO (dl_vdso_getrandom) (buffer,
- length,
- flags | GRND_NONBLOCK,
- state,
- state_size);
+ long int ret = INTERNAL_VSYSCALL_CALL (GLRO (dl_vdso_getrandom), 5,
+ buffer,
+ length,
+ flags | GRND_NONBLOCK,
+ state,
+ state_size);
if (INTERNAL_SYSCALL_ERROR_P (ret))
{
/* Fallback to the syscall if the kernel would block. */
@@ -241,7 +244,9 @@ __getrandom_early_init (_Bool initial)
uint32_t mmap_flags;
uint32_t reserved[13];
} params;
- if (GLRO(dl_vdso_getrandom) (NULL, 0, 0, ¶ms, ~0UL) == 0)
+ long int ret = INTERNAL_VSYSCALL_CALL (GLRO(dl_vdso_getrandom),
+ 5, NULL, 0, 0, ¶ms, ~0UL);
+ if (! INTERNAL_SYSCALL_ERROR_P (ret))
{
/* Align each opaque state to L1 data cache size to avoid false
sharing. If the size can not be obtained, use the kernel