arc4random: Fix incorrect usage of TEMP_FAILURE_RETRY
Checks
Context |
Check |
Description |
redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
redhat-pt-bot/TryBot-32bit |
success
|
Build for i686
|
linaro-tcwg-bot/tcwg_glibc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_check--master-arm |
success
|
Testing passed
|
Commit Message
The _nocancel functions returns errors as negative values, i. e. -EINTR
for interrupted system call. But TEMP_FAILURE_RETRY expects the errors
as errno, thus using TEMP_FAILURE_RETRY is incorrect here.
Add a customized TEMP_FAILURE_RETRY_NEG macro and use it instead of
TEMP_FAILURE_RETRY to fix the issue.
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
stdlib/arc4random.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
Comments
* Xi Ruoyao:
> The _nocancel functions returns errors as negative values, i. e. -EINTR
> for interrupted system call. But TEMP_FAILURE_RETRY expects the errors
> as errno, thus using TEMP_FAILURE_RETRY is incorrect here.
>
> Add a customized TEMP_FAILURE_RETRY_NEG macro and use it instead of
> TEMP_FAILURE_RETRY to fix the issue.
Or we could change __getrandom_nocancel to use INLINE_SYSCALL_CALL
instead of INTERNAL_SYCALL_CALL.
Thanks,
Florian
On 04/01/24 06:51, Florian Weimer wrote:
> * Xi Ruoyao:
>
>> The _nocancel functions returns errors as negative values, i. e. -EINTR
>> for interrupted system call. But TEMP_FAILURE_RETRY expects the errors
>> as errno, thus using TEMP_FAILURE_RETRY is incorrect here.
>>
>> Add a customized TEMP_FAILURE_RETRY_NEG macro and use it instead of
>> TEMP_FAILURE_RETRY to fix the issue.
>
> Or we could change __getrandom_nocancel to use INLINE_SYSCALL_CALL
> instead of INTERNAL_SYCALL_CALL.
It follows what other _nocancel functions that return a value do. The
__getrandom_nocancel is also used on malloc initialization, but I do
not think touching errno should be an issue.
* Adhemerval Zanella Netto:
> On 04/01/24 06:51, Florian Weimer wrote:
>> * Xi Ruoyao:
>>
>>> The _nocancel functions returns errors as negative values, i. e. -EINTR
>>> for interrupted system call. But TEMP_FAILURE_RETRY expects the errors
>>> as errno, thus using TEMP_FAILURE_RETRY is incorrect here.
>>>
>>> Add a customized TEMP_FAILURE_RETRY_NEG macro and use it instead of
>>> TEMP_FAILURE_RETRY to fix the issue.
>>
>> Or we could change __getrandom_nocancel to use INLINE_SYSCALL_CALL
>> instead of INTERNAL_SYCALL_CALL.
>
> It follows what other _nocancel functions that return a value do. The
> __getrandom_nocancel is also used on malloc initialization, but I do
> not think touching errno should be an issue.
It's inconsistent. Most of the implementations in
sysdeps/unix/sysv/linux/*_nocancel*.c use INLINE_SYSCALL_CALL, and
therefore set errno.
Thanks,
Florian
On 04/01/24 09:16, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
>
>> On 04/01/24 06:51, Florian Weimer wrote:
>>> * Xi Ruoyao:
>>>
>>>> The _nocancel functions returns errors as negative values, i. e. -EINTR
>>>> for interrupted system call. But TEMP_FAILURE_RETRY expects the errors
>>>> as errno, thus using TEMP_FAILURE_RETRY is incorrect here.
>>>>
>>>> Add a customized TEMP_FAILURE_RETRY_NEG macro and use it instead of
>>>> TEMP_FAILURE_RETRY to fix the issue.
>>>
>>> Or we could change __getrandom_nocancel to use INLINE_SYSCALL_CALL
>>> instead of INTERNAL_SYCALL_CALL.
>>
>> It follows what other _nocancel functions that return a value do. The
>> __getrandom_nocancel is also used on malloc initialization, but I do
>> not think touching errno should be an issue.
>
> It's inconsistent. Most of the implementations in
> sysdeps/unix/sysv/linux/*_nocancel*.c use INLINE_SYSCALL_CALL, and
> therefore set errno.
I meant that *your suggestion* follow what other _nocancel functions that
return a value do (sorry for the miscommunication).
On Thu, 2024-01-04 at 09:31 -0300, Adhemerval Zanella Netto wrote:
>
>
> On 04/01/24 09:16, Florian Weimer wrote:
> > * Adhemerval Zanella Netto:
> >
> > > On 04/01/24 06:51, Florian Weimer wrote:
> > > > * Xi Ruoyao:
> > > >
> > > > > The _nocancel functions returns errors as negative values, i. e. -EINTR
> > > > > for interrupted system call. But TEMP_FAILURE_RETRY expects the errors
> > > > > as errno, thus using TEMP_FAILURE_RETRY is incorrect here.
> > > > >
> > > > > Add a customized TEMP_FAILURE_RETRY_NEG macro and use it instead of
> > > > > TEMP_FAILURE_RETRY to fix the issue.
> > > >
> > > > Or we could change __getrandom_nocancel to use INLINE_SYSCALL_CALL
> > > > instead of INTERNAL_SYCALL_CALL.
> > >
> > > It follows what other _nocancel functions that return a value do. The
> > > __getrandom_nocancel is also used on malloc initialization, but I do
> > > not think touching errno should be an issue.
> >
> > It's inconsistent. Most of the implementations in
> > sysdeps/unix/sysv/linux/*_nocancel*.c use INLINE_SYSCALL_CALL, and
> > therefore set errno.
>
> I meant that *your suggestion* follow what other _nocancel functions that
> return a value do (sorry for the miscommunication).
Phew, I mistakenly assumed all _nocancel functions did not use errno.
So this patch is wrong and I'll make a V2.
@@ -30,6 +30,15 @@ arc4random_getrandom_failure (void)
__libc_fatal ("Fatal glibc error: cannot get entropy for arc4random\n");
}
+/* Special version of TEMP_FAILURE_RETRY for error values as negative
+ values. */
+#define TEMP_FAILURE_RETRY_NEG(expression) \
+ (__extension__ \
+ ({ long int __result; \
+ do __result = (long int) (expression); \
+ while (__result == -EINTR); \
+ __result; }))
+
void
__arc4random_buf (void *p, size_t n)
{
@@ -42,7 +51,7 @@ __arc4random_buf (void *p, size_t n)
for (;;)
{
- l = TEMP_FAILURE_RETRY (__getrandom_nocancel (p, n, 0));
+ l = TEMP_FAILURE_RETRY_NEG (__getrandom_nocancel (p, n, 0));
if (l > 0)
{
if ((size_t) l == n)
@@ -60,24 +69,24 @@ __arc4random_buf (void *p, size_t n)
{
/* Poll /dev/random as an approximation of RNG initialization. */
struct pollfd pfd = { .events = POLLIN };
- pfd.fd = TEMP_FAILURE_RETRY (
+ pfd.fd = TEMP_FAILURE_RETRY_NEG (
__open64_nocancel ("/dev/random", O_RDONLY | O_CLOEXEC | O_NOCTTY));
if (pfd.fd < 0)
arc4random_getrandom_failure ();
- if (TEMP_FAILURE_RETRY (__poll_infinity_nocancel (&pfd, 1)) < 0)
+ if (TEMP_FAILURE_RETRY_NEG (__poll_infinity_nocancel (&pfd, 1)) < 0)
arc4random_getrandom_failure ();
if (__close_nocancel (pfd.fd) < 0)
arc4random_getrandom_failure ();
atomic_store_relaxed (&seen_initialized, 1);
}
- fd = TEMP_FAILURE_RETRY (
+ fd = TEMP_FAILURE_RETRY_NEG (
__open64_nocancel ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY));
if (fd < 0)
arc4random_getrandom_failure ();
for (;;)
{
- l = TEMP_FAILURE_RETRY (__read_nocancel (fd, p, n));
+ l = TEMP_FAILURE_RETRY_NEG (__read_nocancel (fd, p, n));
if (l <= 0)
arc4random_getrandom_failure ();
if ((size_t) l == n)