Bug 32440 - getrandom() in glibc 2.41 (development) returns EINVAL as retcode instead of errno on powerpc64le
Summary: getrandom() in glibc 2.41 (development) returns EINVAL as retcode instead of ...
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.41
: P1 critical
Target Milestone: 2.41
Assignee: Florian Weimer
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-12-10 11:13 UTC by Ján Stanček
Modified: 2024-12-17 13:51 UTC (History)
6 users (show)

See Also:
Host:
Target: powerpc*-linux-gnu
Build:
Last reconfirmed: 2024-12-10 00:00:00
Project(s) to access:
ssh public key:
fweimer: security+


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ján Stanček 2024-12-10 11:13:01 UTC
-------------------------- 8< ------------------------------
#include <sys/random.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
        char buf[50];
        int ret = getrandom(buf, 50, -1);
        printf("%d %d\n", ret, errno);
}
-------------------------- 8< ------------------------------

using VDSO implementation (the defalut) it returns:
# ./a.out 
22 0

while I'd expect -1 22 - same as returned by "syscall(__NR_getrandom, 50, -1)"
Comment 1 Ján Stanček 2024-12-10 11:15:45 UTC
Used kernel is 6.13-rc1 on Fedora 42.
Comment 2 Florian Weimer 2024-12-10 13:23:34 UTC
Huh. What are your exact glibc and kernel package versions? I do not see this with:

glibc-2.40.9000-21.fc42.x86_64
kernel-6.13.0-0.rc1.20241206gitb8f52214c61a.19.fc42.x86_64
Comment 3 Ján Stanček 2024-12-10 13:30:41 UTC
Same ones, but it's a ppc64le arch:

# uname -r
6.13.0-0.rc1.20241206gitb8f52214c61a.19.eln144.ppc64le

# rpm -qa glibc
glibc-2.40.9000-21.eln144.ppc64le
Comment 4 Florian Weimer 2024-12-10 16:56:01 UTC
The issue is specific to POWER. I'm testing a fix.

It's a security vulnerability, but glibc won't assign a CVE ID for this because it's not in a released version. We'll need a Fedora-specific CVE ID for this.
Comment 5 Florian Weimer 2024-12-10 17:06:50 UTC
Introduced by:

commit 461cab1de747f3842f27a5d24977d78d561d45f9
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Sep 18 16:01:22 2024 +0200

    linux: Add support for getrandom vDSO
    
    Linux 6.11 has getrandom() in vDSO. It operates on a thread-local opaque
    state allocated with mmap using flags specified by the vDSO.
    
    Multiple states are allocated at once, as many as fit into a page, and
    these are held in an array of available states to be doled out to each
    thread upon first use, and recycled when a thread terminates. As these
    states run low, more are allocated.
    
    To make this procedure async-signal-safe, a simple guard is used in the
    LSB of the opaque state address, falling back to the syscall if there's
    reentrancy contention.
    
    Also, _Fork() is handled by blocking signals on opaque state allocation
    (so _Fork() always sees a consistent state even if it interrupts a
    getrandom() call) and by iterating over the thread stack cache on
    reclaim_stack. Each opaque state will be in the free states list
    (grnd_alloc.states) or allocated to a running thread.
    
    The cancellation is handled by always using GRND_NONBLOCK flags while
    calling the vDSO, and falling back to the cancellable syscall if the
    kernel returns EAGAIN (would block). Since getrandom is not defined by
    POSIX and cancellation is supported as an extension, the cancellation is
    handled as 'may occur' instead of 'shall occur' [1], meaning that if
    vDSO does not block (the expected behavior) getrandom will not act as a
    cancellation entrypoint. It avoids a pthread_testcancel call on the fast
    path (different than 'shall occur' functions, like sem_wait()).
    
    It is currently enabled for x86_64, which is available in Linux 6.11,
    and aarch64, powerpc32, powerpc64, loongarch64, and s390x, which are
    available in Linux 6.12.
    
    Link: https://pubs.opengroup.org/onlinepubs/9799919799/nframe.html [1]
    Co-developed-by: Jason A. Donenfeld <Jason@zx2c4.com>
    Tested-by: Jason A. Donenfeld <Jason@zx2c4.com> # x86_64
    Tested-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> # x86_64, aarch64
    Tested-by: Xi Ruoyao <xry111@xry111.site> # x86_64, aarch64, loongarch64
    Tested-by: Stefan Liebler <stli@linux.ibm.com> # s390x

This was backported into Fedora 40 (not yet released) and Fedora 41. It was not backported upstream. So this is technically not a glibc upstream security vulnerability.
Comment 6 Florian Weimer 2024-12-10 17:47:42 UTC
Patch posted:

[PATCH] powerpc: Use correct procedure call standard for getrandom vDSO call (bug 32440)
<https://inbox.sourceware.org/libc-alpha/87v7vr1lf0.fsf@oldenburg.str.redhat.com/>
Comment 7 Carlos O'Donell 2024-12-11 14:58:25 UTC
Reviewing v2.
Comment 8 Florian Weimer 2024-12-11 16:50:59 UTC
Fixed in 2.41 via:

commit 4f5704ea347e52ac3f272d1341da10aed6e9973e
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Dec 10 16:17:06 2024 +0100

    powerpc: Use correct procedure call standard for getrandom vDSO call (bug 32440)
    
    A plain indirect function call does not work on POWER because
    success and failure are signaled through a flag register, and
    not via the usual Linux negative return value convention.
    
    This has potential security impact, in two ways: the return value
    could be out of bounds (EAGAIN is 11 on powerpc6le), and no
    random bytes have been written despite the non-error return value.
    
    Fixes commit 461cab1de747f3842f27a5d24977d78d561d45f9 ("linux: Add
    support for getrandom vDSO").
    
    Reported-by: Ján Stanček <jstancek@redhat.com>
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Comment 9 Florian Weimer 2024-12-11 16:53:30 UTC
Red Hat has assigned CVE-2024-12455 to this issue (as far as Fedora is concerned).