Fix getrandom detection with musl libc #843

Merged
okning merged 3 commits from fix/musl-getrandom into development 2026-09-03 13:32:12 -05:00
okning commented 2026-07-21 10:20:11 -05:00 (Migrated from github.com)

Description

On Linux, the platform entropy implementation currently enables the
getrandom syscall path only for glibc and Midipix. This excludes musl and
other libc implementations that can use the same syscall path, so affected
builds fall back to /dev/random. On older Linux kernels, a subsequent
process may block during PSA crypto initialization after earlier reads
have depleted the available entropy count.

Use __has_include(<sys/syscall.h>) on Linux when supported by the
compiler, and enable the existing syscall wrapper only when
SYS_getrandom is defined. Preserve the glibc/Midipix condition for older
toolchains and the existing fallback when the kernel returns ENOSYS.

The initial <sys/random.h>/libc-wrapper detection was replaced during
review because it broke dietlibc builds. The final implementation reuses
syscall(SYS_getrandom, ...) and adds no public configuration option.

Validation

Manual validation of this development PR, reported on August 3:

  • glibc 2.43 / GCC 16.1: build passed; syscall path selected; two consecutive initializations passed.
  • musl / GCC 12.4: full build passed; syscall path selected; two consecutive initializations passed.
  • dietlibc 0.34: build passed; SYS_getrandom is absent and the existing fallback remained selected.
  • uClibc-ng 1.0.54 / GCC 14.3: static build passed; syscall path selected; two consecutive initializations passed.
  • Android bionic / NDK r29 / API 21 / x86_64: dynamic and static builds passed; syscall path selected; the static binary passed two consecutive initializations.
  • AppleClang 21 Debug build passed, followed by 132/132 CTest tests.
  • ChangeLog assembly check passed.

The individual backport PRs document their separate validation results.

PR checklist

  • changelog provided.
  • framework PR not required.
  • TF-PSA-Crypto development PR this PR.
  • TF-PSA-Crypto 1.1 PR Mbed-TLS/TF-PSA-Crypto#893.
  • mbedtls development PR not required because the implementation is maintained in TF-PSA-Crypto.
  • mbedtls 4.1 PR not provided; the corresponding submodule update can follow the TF-PSA-Crypto backport.
  • mbedtls 3.6 PR Mbed-TLS/mbedtls#10945.
  • tests no new committed test cases; manual libc testing was accepted during review and is recorded above.
## Description On Linux, the platform entropy implementation currently enables the getrandom syscall path only for glibc and Midipix. This excludes musl and other libc implementations that can use the same syscall path, so affected builds fall back to `/dev/random`. On older Linux kernels, a subsequent process may block during PSA crypto initialization after earlier reads have depleted the available entropy count. Use `__has_include(<sys/syscall.h>)` on Linux when supported by the compiler, and enable the existing syscall wrapper only when `SYS_getrandom` is defined. Preserve the glibc/Midipix condition for older toolchains and the existing fallback when the kernel returns `ENOSYS`. The initial `<sys/random.h>`/libc-wrapper detection was replaced during review because it broke dietlibc builds. The final implementation reuses `syscall(SYS_getrandom, ...)` and adds no public configuration option. ## Validation Manual validation of this development PR, reported on August 3: - glibc 2.43 / GCC 16.1: build passed; syscall path selected; two consecutive initializations passed. - musl / GCC 12.4: full build passed; syscall path selected; two consecutive initializations passed. - dietlibc 0.34: build passed; `SYS_getrandom` is absent and the existing fallback remained selected. - uClibc-ng 1.0.54 / GCC 14.3: static build passed; syscall path selected; two consecutive initializations passed. - Android bionic / NDK r29 / API 21 / x86_64: dynamic and static builds passed; syscall path selected; the static binary passed two consecutive initializations. - AppleClang 21 Debug build passed, followed by 132/132 CTest tests. - ChangeLog assembly check passed. The individual backport PRs document their separate validation results. ## PR checklist - [x] **changelog** provided. - [x] **framework PR** not required. - [x] **TF-PSA-Crypto development PR** this PR. - [x] **TF-PSA-Crypto 1.1 PR** Mbed-TLS/TF-PSA-Crypto#893. - [x] **mbedtls development PR** not required because the implementation is maintained in TF-PSA-Crypto. - [x] **mbedtls 4.1 PR** not provided; the corresponding submodule update can follow the TF-PSA-Crypto backport. - [x] **mbedtls 3.6 PR** Mbed-TLS/mbedtls#10945. - **tests** no new committed test cases; manual libc testing was accepted during review and is recorded above.
gilles-peskine-arm (Migrated from github.com) requested changes 2026-07-29 13:26:21 -05:00
gilles-peskine-arm (Migrated from github.com) left a comment

I'm all for improving the library on musl, but not if it breaks the build elsewhere.

The right thing to do would be to guard the non-portable code with #if __MUSL__ or some such. But since this does not and will not exist, I'm afraid we're stuck. We could add a way to declare “I swear I have getrandom()” at compile time. But that's even more complexity in code that's already more complex than I'd like. So I'd want to set up some testing if we do that, and that's complicated.

I'm all for improving the library on musl, but not if it breaks the build elsewhere. The right thing to do would be to guard the non-portable code with `#if __MUSL__` or some such. But [since this does not and will not exist](https://www.openwall.com/lists/musl/2026/04/11/5), I'm afraid we're stuck. We could add a way to declare “I swear I have `getrandom()`” at compile time. But that's even more complexity in code that's already more complex than I'd like. So I'd want to set up some testing if we do that, and that's complicated.
@ -0,0 +1,5 @@
Features
gilles-peskine-arm (Migrated from github.com) commented 2026-07-29 13:23:22 -05:00

I wouldn't consider this a bug in TF-PSA-Crypto (but a bug in older Linux kernels). We're just not taking advantage of a nicer feature exposed by musl.

I wouldn't consider this a bug in TF-PSA-Crypto (but a bug in older Linux kernels). We're just not taking advantage of a nicer feature exposed by musl.
@ -298,0 +296,4 @@
#if defined(__linux__) && defined(__has_include)
#if __has_include(<sys/syscall.h>)
#define MBEDTLS_PLATFORM_HAS_SYS_SYSCALL_H
#endif
gilles-peskine-arm (Migrated from github.com) commented 2026-07-29 13:21:15 -05:00

This breaks the build with dietlibc.

  CC    source/platform/platform_util.c
In file included from source/platform/platform_util.c:305:
/usr/include/x86_64-linux-gnu/sys/random.h: In function ‘getrandom’:
/usr/include/x86_64-linux-gnu/sys/random.h:35:42: error: unknown type name ‘__wur’; did you mean ‘__wsum’?
   35 |                    unsigned int __flags) __wur
      |                                          ^~~~~
      |                                          __wsum
/usr/include/x86_64-linux-gnu/sys/random.h:36:35: error: expected declaration specifiers or ‘...’ before ‘(’ token
   36 |                    __attr_access ((__write_only__, 1, 2));
      |                                   ^
/usr/include/x86_64-linux-gnu/sys/random.h:40:50: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘__wur’
   40 | int getentropy (void *__buffer, size_t __length) __wur
      |                                                  ^~~~~
source/platform/platform_util.c:309:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or __attribute__’ before ‘{’ token
  309 | {
      | ^
source/platform/platform_util.c:387:1: error: parameter ‘mbedtls_platform_dev_random’ is initialized
  387 | const char *mbedtls_platform_dev_random = MBEDTLS_PLATFORM_DEV_RANDOM;
      | ^~~~~
source/platform/platform_util.c:392:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or __attribute__’ before ‘{’ token
  392 | {
      | ^
/usr/include/x86_64-linux-gnu/sys/random.h:34:9: error: old-style parameter declarations in prototyped function definition
   34 | ssize_t getrandom (void *__buffer, size_t __length,
      |         ^~~~~~~~~
source/platform/platform_util.c:447: error: expected ‘{’ at end of input
source/platform/platform_util.c:447: error: control reaches end of non-void function [-Werror=return-type]
cc1: all warnings being treated as errors
make: *** [Makefile:11984: platform/platform_util.o] Error 1

(on Ubuntu 24.04)

(I'm pretty sure that's why I didn't do that when I overhauled our random-on-Linux code recently.)

This breaks the build with dietlibc. ``` CC source/platform/platform_util.c In file included from source/platform/platform_util.c:305: /usr/include/x86_64-linux-gnu/sys/random.h: In function ‘getrandom’: /usr/include/x86_64-linux-gnu/sys/random.h:35:42: error: unknown type name ‘__wur’; did you mean ‘__wsum’? 35 | unsigned int __flags) __wur | ^~~~~ | __wsum /usr/include/x86_64-linux-gnu/sys/random.h:36:35: error: expected declaration specifiers or ‘...’ before ‘(’ token 36 | __attr_access ((__write_only__, 1, 2)); | ^ /usr/include/x86_64-linux-gnu/sys/random.h:40:50: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘__wur’ 40 | int getentropy (void *__buffer, size_t __length) __wur | ^~~~~ source/platform/platform_util.c:309:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or __attribute__’ before ‘{’ token 309 | { | ^ source/platform/platform_util.c:387:1: error: parameter ‘mbedtls_platform_dev_random’ is initialized 387 | const char *mbedtls_platform_dev_random = MBEDTLS_PLATFORM_DEV_RANDOM; | ^~~~~ source/platform/platform_util.c:392:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or __attribute__’ before ‘{’ token 392 | { | ^ /usr/include/x86_64-linux-gnu/sys/random.h:34:9: error: old-style parameter declarations in prototyped function definition 34 | ssize_t getrandom (void *__buffer, size_t __length, | ^~~~~~~~~ source/platform/platform_util.c:447: error: expected ‘{’ at end of input source/platform/platform_util.c:447: error: control reaches end of non-void function [-Werror=return-type] cc1: all warnings being treated as errors make: *** [Makefile:11984: platform/platform_util.o] Error 1 ``` (on Ubuntu 24.04) (I'm pretty sure that's why I didn't do that when I overhauled our random-on-Linux code recently.)
okning commented 2026-07-31 10:37:45 -05:00 (Migrated from github.com)

Thanks, you're right — checking only for the presence of <sys/random.h> is insufficient and causes a regression for dietlibc. I'll remove the automatic detection and reclassify the changelog entry as a feature.

Before updating the implementation, would you be open to an explicit opt-in configuration macro, for example MBEDTLS_PLATFORM_HAS_GETRANDOM? The default behavior would remain unchanged, and the libc wrapper would only be used when the integrator explicitly declares it available. I would add build coverage for both the enabled path and the unchanged fallback path, while retaining the musl/QEMU consecutive-initialization validation.

Thanks, you're right — checking only for the presence of `<sys/random.h>` is insufficient and causes a regression for dietlibc. I'll remove the automatic detection and reclassify the changelog entry as a feature. Before updating the implementation, would you be open to an explicit opt-in configuration macro, for example `MBEDTLS_PLATFORM_HAS_GETRANDOM`? The default behavior would remain unchanged, and the libc wrapper would only be used when the integrator explicitly declares it available. I would add build coverage for both the enabled path and the unchanged fallback path, while retaining the musl/QEMU consecutive-initialization validation.
gilles-peskine-arm commented 2026-08-03 07:14:35 -05:00 (Migrated from github.com)

We prefer to keep the number of compile-time options down, but if that's the only way, we'll accept it.

But there's one thing I'm not sure I've tried: maybe the block that uses syscall(SYS_getrandom, ...) would work on the platforms where __has_include(<sys/syscall.h>) works? Would you mind checking how that goes with dietlibc and musl and anything else you have easy access to?

Ideally we'd like this to be covered in our CI, but that would require more work on our CI images than we have time for at the moment. So we'll settle for manual testing for now.

We prefer to keep the number of compile-time options down, but if that's the only way, we'll accept it. But there's one thing I'm not sure I've tried: maybe the block that uses `syscall(SYS_getrandom, ...)` would work on the platforms where `__has_include(<sys/syscall.h>)` works? Would you mind checking how that goes with dietlibc and musl and anything else you have easy access to? Ideally we'd like this to be covered in our CI, but that would require more work on our CI images than we have time for at the moment. So we'll settle for manual testing for now.
okning commented 2026-08-03 08:38:36 -05:00 (Migrated from github.com)

That's a great idea—thanks for pointing it out. I replaced the
<sys/random.h>/libc-wrapper detection with a guarded raw-syscall path:

  • On Linux, use __has_include(<sys/syscall.h>) when available.
  • Only enable the syscall path when SYS_getrandom is defined.
  • Retain the existing glibc/Midipix condition for older toolchains.
  • Otherwise preserve the existing /dev/random fallback.

I also reclassified the changelog entry as a feature.

Validation performed:

  • glibc 2.43 / GCC 16.1: build passed; syscall path selected; two
    consecutive initializations passed.
  • musl / GCC 12.4: full build passed; syscall path selected; two
    consecutive initializations passed.
  • dietlibc 0.34: <sys/syscall.h> is present but SYS_getrandom is not
    defined; the build passed and the existing fallback remained selected.
    This avoids the <sys/random.h> regression.
  • uClibc-ng 1.0.54 / GCC 14.3: static build passed; syscall path selected;
    two consecutive initializations passed.
  • Android bionic / NDK r29 / API 21 / x86_64: dynamic and static builds
    passed; syscall path selected; the static binary passed two consecutive
    initializations.
  • AppleClang 21 Debug build passed, followed by 132/132 CTest tests.
That's a great idea—thanks for pointing it out. I replaced the `<sys/random.h>`/libc-wrapper detection with a guarded raw-syscall path: - On Linux, use `__has_include(<sys/syscall.h>)` when available. - Only enable the syscall path when `SYS_getrandom` is defined. - Retain the existing glibc/Midipix condition for older toolchains. - Otherwise preserve the existing `/dev/random` fallback. I also reclassified the changelog entry as a feature. Validation performed: - glibc 2.43 / GCC 16.1: build passed; syscall path selected; two consecutive initializations passed. - musl / GCC 12.4: full build passed; syscall path selected; two consecutive initializations passed. - dietlibc 0.34: `<sys/syscall.h>` is present but `SYS_getrandom` is not defined; the build passed and the existing fallback remained selected. This avoids the `<sys/random.h>` regression. - uClibc-ng 1.0.54 / GCC 14.3: static build passed; syscall path selected; two consecutive initializations passed. - Android bionic / NDK r29 / API 21 / x86_64: dynamic and static builds passed; syscall path selected; the static binary passed two consecutive initializations. - AppleClang 21 Debug build passed, followed by 132/132 CTest tests.
gilles-peskine-arm (Migrated from github.com) reviewed 2026-08-03 10:02:03 -05:00
gilles-peskine-arm (Migrated from github.com) left a comment
No description provided.
LGTM
okning (Migrated from github.com) reviewed 2026-08-03 10:08:24 -05:00
@ -0,0 +1,5 @@
Features
okning (Migrated from github.com) commented 2026-08-03 10:08:24 -05:00

I've removed the Markdown backticks and changed it to the conventional getrandom() spelling.

I've removed the Markdown backticks and changed it to the conventional getrandom() spelling.
gilles-peskine-arm (Migrated from github.com) approved these changes 2026-08-03 10:09:50 -05:00
gilles-peskine-arm (Migrated from github.com) left a comment

LGTM

LGTM
davidhorstmann-arm (Migrated from github.com) approved these changes 2026-09-03 05:50:02 -05:00
davidhorstmann-arm (Migrated from github.com) left a comment

LGTM, thanks!

Can you make a backport to 1.1 and Mbed TLS 3.6? Then we can merge.

LGTM, thanks! Can you make a backport to 1.1 and Mbed TLS 3.6? Then we can merge.
okning commented 2026-09-03 05:58:40 -05:00 (Migrated from github.com)

Thanks! I’ll prepare the backports to TF-PSA-Crypto 1.1 and Mbed TLS 3.6.

Thanks! I’ll prepare the backports to TF-PSA-Crypto 1.1 and Mbed TLS 3.6.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-Mbed-TLS/TF-PSA-Crypto!843
No description provided.