Обсуждение: Support getrandom() for pg_strong_random() source
Hi all, Currently we have three options for pg_strong_random() sources: 1. OpenSSL's RAND_bytes() 2. Windows' CryptGenRandom() function 3. /dev/urandom The patch supports the getrandom() function as a new source of pg_strong_random(). The getrandom() function uses the same source as the /dev/urandom device but it seems much faster than opening, reading, and closing /dev/urandom. Here is the execution time of generating 1 million UUIDv4 data measured on my environment: HEAD(/dev/urandom): 1863.064 ms Patched(getrandom()): 516.627 ms I guess that while OpenSSL's RAND_bytes() should still be prioritized where available it might be a good idea to support getrandom() for builds where RAND_bytes() is not available. Feedback is very welcome. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
Вложения
On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote: > The patch supports the getrandom() function as a new source of > pg_strong_random(). The getrandom() function uses the same source as > the /dev/urandom device but it seems much faster than opening, > reading, and closing /dev/urandom. Here is the execution time of > generating 1 million UUIDv4 data measured on my environment: > > HEAD(/dev/urandom): 1863.064 ms > Patched(getrandom()): 516.627 ms Interesting. Are there platforms where this is not available? I'd be pretty sure that some animals in the buildfarm would not like this suggestion but I'm saying it anyway. Perhaps we could even drop /dev/urandom? > I guess that while OpenSSL's RAND_bytes() should still be prioritized > where available it might be a good idea to support getrandom() for > builds where RAND_bytes() is not available. > > Feedback is very welcome. I am wondering how much non-OpenSSL builds matter these days, TBH, so I am not sure that this is worth the addition of an extra configure/meson check and this stuff has its cost just for such builds. I am not saying that we should make OpenSSL mandatory, of course not, but all production instances of Postgres have likely OpenSSL enabled anyway. Perhaps some embedded deployments like --without-openssl, who knows.. -- Michael
Вложения
On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote: > > On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote: > > The patch supports the getrandom() function as a new source of > > pg_strong_random(). The getrandom() function uses the same source as > > the /dev/urandom device but it seems much faster than opening, > > reading, and closing /dev/urandom. Here is the execution time of > > generating 1 million UUIDv4 data measured on my environment: > > > > HEAD(/dev/urandom): 1863.064 ms > > Patched(getrandom()): 516.627 ms > > Interesting. Are there platforms where this is not available? I'd be > pretty sure that some animals in the buildfarm would not like this > suggestion but I'm saying it anyway. Perhaps we could even drop > /dev/urandom? As far as I know macOS doesn't support getrandom() but supports getentropy() instead. And an older glibc version might not support it. It's supported since Linux 3.17 and glibc 2.25. > > I guess that while OpenSSL's RAND_bytes() should still be prioritized > > where available it might be a good idea to support getrandom() for > > builds where RAND_bytes() is not available. > > > > Feedback is very welcome. > > I am wondering how much non-OpenSSL builds matter these days, TBH, so > I am not sure that this is worth the addition of an extra > configure/meson check and this stuff has its cost just for such > builds. I am not saying that we should make OpenSSL mandatory, of > course not, but all production instances of Postgres have likely > OpenSSL enabled anyway. Perhaps some embedded deployments like > --without-openssl, who knows.. Fair point. In fact, I was not using OpenSSL and just realized generating UUID by PostgreSQL's uuidv4() and uuidv7() was much slower than generating it by Rust's UUID crate. On my environment, getrandom() is faster than RAND_bytes() so I thought there are some cases where users want to use the getrandom() source rather than RAND_bytes(), but I'm not sure since there is also a difference in the secureness. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
Masahiko Sawada <sawada.mshk@gmail.com> writes: > On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote: >> >> On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote: >> > The patch supports the getrandom() function as a new source of >> > pg_strong_random(). The getrandom() function uses the same source as >> > the /dev/urandom device but it seems much faster than opening, >> > reading, and closing /dev/urandom. Here is the execution time of >> > generating 1 million UUIDv4 data measured on my environment: >> > >> > HEAD(/dev/urandom): 1863.064 ms >> > Patched(getrandom()): 516.627 ms >> >> Interesting. Are there platforms where this is not available? I'd be >> pretty sure that some animals in the buildfarm would not like this >> suggestion but I'm saying it anyway. Perhaps we could even drop >> /dev/urandom? > > As far as I know macOS doesn't support getrandom() but supports > getentropy() instead. And an older glibc version might not support it. > It's supported since Linux 3.17 and glibc 2.25. getrandom() is Linux-specific, while getentropy() is specified by POSIX (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024 Sources: https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html https://dotat.at/@/2024-10-01-getentropy.html So I think it's more worthwhile to add support for getentropy() than getrandom(). - ilmari
On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> wrote: > > Masahiko Sawada <sawada.mshk@gmail.com> writes: > > > On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote: > >> > >> On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote: > >> > The patch supports the getrandom() function as a new source of > >> > pg_strong_random(). The getrandom() function uses the same source as > >> > the /dev/urandom device but it seems much faster than opening, > >> > reading, and closing /dev/urandom. Here is the execution time of > >> > generating 1 million UUIDv4 data measured on my environment: > >> > > >> > HEAD(/dev/urandom): 1863.064 ms > >> > Patched(getrandom()): 516.627 ms > >> > >> Interesting. Are there platforms where this is not available? I'd be > >> pretty sure that some animals in the buildfarm would not like this > >> suggestion but I'm saying it anyway. Perhaps we could even drop > >> /dev/urandom? > > > > As far as I know macOS doesn't support getrandom() but supports > > getentropy() instead. And an older glibc version might not support it. > > It's supported since Linux 3.17 and glibc 2.25. > > getrandom() is Linux-specific, while getentropy() is specified by POSIX > (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and > was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in > 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024 > > Sources: > > https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html > https://dotat.at/@/2024-10-01-getentropy.html > > So I think it's more worthwhile to add support for getentropy() than > getrandom(). While getentropy() has better portability, according to the getentropy() manual, the maximum length is limited to 256 bytes. It works in some cases such as generating UUID data but seems not appropriate for our general pg_strong_random() use cases. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Tue, Jul 22, 2025 at 11:32 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > While getentropy() has better portability, according to the > getentropy() manual, the maximum length is limited to 256 bytes. It > works in some cases such as generating UUID data but seems not > appropriate for our general pg_strong_random() use cases. I imagine that the code would look very similar to your patch, though (loop, in chunks of size GETENTROPY_MAX, until the required length is met). Without looking too deeply, I have to say that implementing a newer POSIX API as opposed to a Linux-specific one does seem like a better cost-benefit tradeoff, if we decide to do this. Can you talk more about this part: > On my environment, > getrandom() is faster than RAND_bytes() so I thought there are some > cases where users want to use the getrandom() source rather than > RAND_bytes(), but I'm not sure since there is also a difference in the > secureness. That is _really_ surprising to me at first glance. I thought RAND_bytes() was supposed to be a userspace PRNG, which I would naively expect to take much less time than pulling data from Linux. (Once the OpenSSL PRNG has been seeded, that is.) Are there any other details about your environment (or the test itself) that are unusual? Thanks, --Jacob
Hi ,
On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:
>
> Masahiko Sawada <sawada.mshk@gmail.com> writes:
>
> > On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:
> >>
> >> On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:
> >> > The patch supports the getrandom() function as a new source of
> >> > pg_strong_random(). The getrandom() function uses the same source as
> >> > the /dev/urandom device but it seems much faster than opening,
> >> > reading, and closing /dev/urandom. Here is the execution time of
> >> > generating 1 million UUIDv4 data measured on my environment:
> >> >
> >> > HEAD(/dev/urandom): 1863.064 ms
> >> > Patched(getrandom()): 516.627 ms
> >>
> >> Interesting. Are there platforms where this is not available? I'd be
> >> pretty sure that some animals in the buildfarm would not like this
> >> suggestion but I'm saying it anyway. Perhaps we could even drop
> >> /dev/urandom?
> >
> > As far as I know macOS doesn't support getrandom() but supports
> > getentropy() instead. And an older glibc version might not support it.
> > It's supported since Linux 3.17 and glibc 2.25.
>
> getrandom() is Linux-specific, while getentropy() is specified by POSIX
> (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
> was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
> 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024
>
> Sources:
>While getentropy() has better portability, according to the
>getentropy() manual, the maximum length is limited to 256 bytes. It
>works in some cases such as generating UUID data but seems not
> appropriate for our general pg_strong_random() use cases.
<ilmari@ilmari.org> wrote:
>
> Masahiko Sawada <sawada.mshk@gmail.com> writes:
>
> > On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:
> >>
> >> On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:
> >> > The patch supports the getrandom() function as a new source of
> >> > pg_strong_random(). The getrandom() function uses the same source as
> >> > the /dev/urandom device but it seems much faster than opening,
> >> > reading, and closing /dev/urandom. Here is the execution time of
> >> > generating 1 million UUIDv4 data measured on my environment:
> >> >
> >> > HEAD(/dev/urandom): 1863.064 ms
> >> > Patched(getrandom()): 516.627 ms
> >>
> >> Interesting. Are there platforms where this is not available? I'd be
> >> pretty sure that some animals in the buildfarm would not like this
> >> suggestion but I'm saying it anyway. Perhaps we could even drop
> >> /dev/urandom?
> >
> > As far as I know macOS doesn't support getrandom() but supports
> > getentropy() instead. And an older glibc version might not support it.
> > It's supported since Linux 3.17 and glibc 2.25.
>
> getrandom() is Linux-specific, while getentropy() is specified by POSIX
> (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
> was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
> 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024
>
> Sources:
>While getentropy() has better portability, according to the
>getentropy() manual, the maximum length is limited to 256 bytes. It
>works in some cases such as generating UUID data but seems not
> appropriate for our general pg_strong_random() use cases.
The
getentropy()
function has a limitation of generating a maximum of 256 bytes of entropy per call and is not supported on Windows platforms. For cryptographic operations that require large buffers of high-quality randomness efficiently, it's not recommended to use getentropy().
In Postgres it’s common to see the SQL random() function used to generate a random number, but it’s a pseudo-random number generator, and not suitable for cases where real randomness is required critical. Postgres also provides a way of getting secure random numbers as well, but only through the use of the pgcrypto extension, which makes gen_random_bytes available. Pulling pgcrypto into ... brandur.org |
Thanks
Regards
Dinesh Nair
From: Masahiko Sawada <sawada.mshk@gmail.com>
Sent: Wednesday, July 23, 2025 12:02 AM
To: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Cc: Michael Paquier <michael@paquier.xyz>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: Support getrandom() for pg_strong_random() source
Sent: Wednesday, July 23, 2025 12:02 AM
To: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Cc: Michael Paquier <michael@paquier.xyz>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: Support getrandom() for pg_strong_random() source
Caution: This email was sent from an external source. Please verify the sender’s identity before clicking links or opening attachments.
On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:
>
> Masahiko Sawada <sawada.mshk@gmail.com> writes:
>
> > On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:
> >>
> >> On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:
> >> > The patch supports the getrandom() function as a new source of
> >> > pg_strong_random(). The getrandom() function uses the same source as
> >> > the /dev/urandom device but it seems much faster than opening,
> >> > reading, and closing /dev/urandom. Here is the execution time of
> >> > generating 1 million UUIDv4 data measured on my environment:
> >> >
> >> > HEAD(/dev/urandom): 1863.064 ms
> >> > Patched(getrandom()): 516.627 ms
> >>
> >> Interesting. Are there platforms where this is not available? I'd be
> >> pretty sure that some animals in the buildfarm would not like this
> >> suggestion but I'm saying it anyway. Perhaps we could even drop
> >> /dev/urandom?
> >
> > As far as I know macOS doesn't support getrandom() but supports
> > getentropy() instead. And an older glibc version might not support it.
> > It's supported since Linux 3.17 and glibc 2.25.
>
> getrandom() is Linux-specific, while getentropy() is specified by POSIX
> (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
> was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
> 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024
>
> Sources:
>
> https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpubs.opengroup.org%2Fonlinepubs%2F9799919799%2Ffunctions%2Fgetentropy.html&data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824005298%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=C5abb70MrRMb8YrRpFZreelrwfXgKtxWYNWvEc3oPFg%3D&reserved=0
> https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdotat.at%2F%40%2F2024-10-01-getentropy.html&data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824035506%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=RwqnnTVGURh7kw31OLW0kRUu%2BCUVVRlt%2Fx9FDDesb58%3D&reserved=0
>
> So I think it's more worthwhile to add support for getentropy() than
> getrandom().
While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.
Regards,
--
Masahiko Sawada
Amazon Web Services: https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Faws.amazon.com%2F&data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824052980%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=NNEQNe%2Fibr6VRZAmBPWTy6r5J4pH2yza4PVGA4E9LO4%3D&reserved=0
On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:
>
> Masahiko Sawada <sawada.mshk@gmail.com> writes:
>
> > On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:
> >>
> >> On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:
> >> > The patch supports the getrandom() function as a new source of
> >> > pg_strong_random(). The getrandom() function uses the same source as
> >> > the /dev/urandom device but it seems much faster than opening,
> >> > reading, and closing /dev/urandom. Here is the execution time of
> >> > generating 1 million UUIDv4 data measured on my environment:
> >> >
> >> > HEAD(/dev/urandom): 1863.064 ms
> >> > Patched(getrandom()): 516.627 ms
> >>
> >> Interesting. Are there platforms where this is not available? I'd be
> >> pretty sure that some animals in the buildfarm would not like this
> >> suggestion but I'm saying it anyway. Perhaps we could even drop
> >> /dev/urandom?
> >
> > As far as I know macOS doesn't support getrandom() but supports
> > getentropy() instead. And an older glibc version might not support it.
> > It's supported since Linux 3.17 and glibc 2.25.
>
> getrandom() is Linux-specific, while getentropy() is specified by POSIX
> (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
> was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
> 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024
>
> Sources:
>
> https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpubs.opengroup.org%2Fonlinepubs%2F9799919799%2Ffunctions%2Fgetentropy.html&data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824005298%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=C5abb70MrRMb8YrRpFZreelrwfXgKtxWYNWvEc3oPFg%3D&reserved=0
> https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdotat.at%2F%40%2F2024-10-01-getentropy.html&data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824035506%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=RwqnnTVGURh7kw31OLW0kRUu%2BCUVVRlt%2Fx9FDDesb58%3D&reserved=0
>
> So I think it's more worthwhile to add support for getentropy() than
> getrandom().
While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.
Regards,
--
Masahiko Sawada
Amazon Web Services: https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Faws.amazon.com%2F&data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824052980%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=NNEQNe%2Fibr6VRZAmBPWTy6r5J4pH2yza4PVGA4E9LO4%3D&reserved=0
On Tue, Jul 22, 2025 at 11:46 AM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Tue, Jul 22, 2025 at 11:32 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > While getentropy() has better portability, according to the > > getentropy() manual, the maximum length is limited to 256 bytes. It > > works in some cases such as generating UUID data but seems not > > appropriate for our general pg_strong_random() use cases. > > I imagine that the code would look very similar to your patch, though > (loop, in chunks of size GETENTROPY_MAX, until the required length is > met). Without looking too deeply, I have to say that implementing a > newer POSIX API as opposed to a Linux-specific one does seem like a > better cost-benefit tradeoff, if we decide to do this. > > Can you talk more about this part: > > > On my environment, > > getrandom() is faster than RAND_bytes() so I thought there are some > > cases where users want to use the getrandom() source rather than > > RAND_bytes(), but I'm not sure since there is also a difference in the > > secureness. > > That is _really_ surprising to me at first glance. I thought > RAND_bytes() was supposed to be a userspace PRNG, which I would > naively expect to take much less time than pulling data from Linux. > (Once the OpenSSL PRNG has been seeded, that is.) Are there any other > details about your environment (or the test itself) that are unusual? Yes, it surprised me too. The environment I used for this benchmark was: % cat /etc/redhat-release Red Hat Enterprise Linux release 8.10 (Ootpa) % uname -r 4.18.0-553.22.1.el8_10.x86_64 % rpm -qa | grep openssl openssl-libs-1.1.1k-14.el8_6.x86_64 openssl-debugsource-1.1.1k-14.el8_6.x86_64 rubygem-openssl-2.1.2-114.module+el8.10.0+23088+750dc6ca.x86_64 openssl-devel-1.1.1k-14.el8_6.x86_64 openssl-pkcs11-0.4.10-3.el8.x86_64 openssl-1.1.1k-14.el8_6.x86_64 openssl-debuginfo-1.1.1k-14.el8_6.x86_64 % openssl version OpenSSL 1.1.1k FIPS 25 Mar 2021 and I measured the execution time of the following query: explain analyze select uuidv4() from generate_series(1, 1_000_000); The result is: getrandom: 517.120ms RAND_bytes: 1150.051 ms /dev/urandom: 1862.483 ms Since on the above environment I used an old Linux kernel and openssl version, I've does the same benchmark on another environment: $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 24.04.2 LTS Release: 24.04 Codename: noble $ apt list --installed | grep ssl libssl-dev/noble-updates,noble-security,now 3.0.13-0ubuntu3.5 amd64 [installed] libssl3t64/noble-updates,noble-security,now 3.0.13-0ubuntu3.5 amd64 [installed,automatic] libxmlsec1t64-openssl/noble,now 1.2.39-5build2 amd64 [installed,automatic] openssl/noble-updates,noble-security,now 3.0.13-0ubuntu3.5 amd64 [installed,automatic] python3-openssl/noble,now 23.2.0-1 all [installed,automatic] ssl-cert/noble,now 1.1.2ubuntu1 all [installed,automatic] The trend of the results were similar: getrandom: 497.061 ms RAND_bytes: 1152.260 ms ms /dev/urandom: 1696.065 ms Please let me know if I'm missing configurations or settings to measure this workload properly. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Tue, Jul 22, 2025 at 4:23 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > The trend of the results were similar: > > getrandom: 497.061 ms > RAND_bytes: 1152.260 ms ms > /dev/urandom: 1696.065 ms > > Please let me know if I'm missing configurations or settings to > measure this workload properly. I don't think you're missing anything, or else I'm missing something too. If I modify pg_strong_random() to call getentropy() in addition to the existing RAND_bytes() code, `perf` shows RAND_bytes() taking up 2.4x the samples that getentropy() does. That's very similar to your results. > On Tue, Jul 22, 2025 at 11:46 AM Jacob Champion > <jacob.champion@enterprisedb.com> wrote: > > That is _really_ surprising to me at first glance. I thought > > RAND_bytes() was supposed to be a userspace PRNG, which I would > > naively expect to take much less time than pulling data from Linux. So my expectation was naive for sure. This has sent me down a bit of a rabbit hole, starting with Adam Langley's BoringSSL post [1] which led to a post/rant on urandom [2]. I don't think an API that advertises "strong randomness" should ever prioritize performance over strength. But maybe the pendulum has swung far enough that we can expect any kernel supporting getentropy() to be able to do the job just as well as OpenSSL does in userspace, except also faster? I think it might be worth a discussion. Thanks, --Jacob [1] https://www.imperialviolet.org/2015/10/17/boringssl.html [2] https://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
> On 23 Jul 2025, at 19:11, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > .. maybe the pendulum has swung far enough that we can expect any > kernel supporting getentropy() to be able to do the job just as well > as OpenSSL does in userspace, except also faster? I think it might be > worth a discussion. There has in the past been discussions (at least off-list in hallway tracks) about allowing randomness to be chosen separately from underlying factors such as OpenSSL support, at the time it didn't seem worth the trouble but that may well have changed. With OpenSSL 1.1.1 being the baseline we can also make use of the _priv_bytes functions to get increased isolation. -- Daniel Gustafsson
On Mon, Jul 28, 2025 at 4:36 AM Daniel Gustafsson <daniel@yesql.se> wrote: > There has in the past been discussions (at least off-list in hallway tracks) > about allowing randomness to be chosen separately from underlying factors such > as OpenSSL support, at the time it didn't seem worth the trouble but that may > well have changed. Yeah, especially if other options with similar strength could be much faster. But the comparison is really going to be OS-dependent [1, 2]. > With OpenSSL 1.1.1 being the baseline we can also make use of the _priv_bytes > functions to get increased isolation. Hmm, that's an interesting idea too. To move this forward a tiny bit: I would be okay with maintaining a new getentropy() case. (I'm less excited about getrandom() because of its reduced reach.) And maybe down the line we should discuss choosing an option at configure time? --Jacob [1] https://lwn.net/Articles/983186/ [2] https://dotat.at/@/2024-10-01-getentropy.html
> On 28 Jul 2025, at 17:29, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > To move this forward a tiny bit: I would be okay with maintaining a > new getentropy() case. (I'm less excited about getrandom() because of > its reduced reach.) And maybe down the line we should discuss choosing > an option at configure time? I would not be opposed to starting there. -- Daniel Gustafsson
On Mon, Jul 28, 2025 at 06:14:20PM +0200, Daniel Gustafsson wrote: > On 28 Jul 2025, at 17:29, Jacob Champion <jacob.champion@enterprisedb.com> wrote: >> To move this forward a tiny bit: I would be okay with maintaining a >> new getentropy() case. (I'm less excited about getrandom() because of >> its reduced reach.) And maybe down the line we should discuss choosing >> an option at configure time? > > I would not be opposed to starting there. Both of you know the options of these areas of the code more than the average committer, I think, so if you think that getentropy() could be a good choice, while making the choice configurable to give the possibility to be outside of OpenSSL, why not. My understanding of the problem is that it is a choice of efficiency vs entropy, and that it's not really possible to have both parts of the cake. If we make that configurable, documentation sounds like the key point to me, to explain which one has more benefits over the other. Could getentropy() be more efficient at the end on most platforms, meaning that this could limit the meaning of having a GUC switch? Having it in POSIX is appealing with the long-term picture in mind.. -- Michael
Вложения
On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote: > My understanding of the problem is that it is a choice of efficiency > vs entropy, and that it's not really possible to have both parts of > the cake. That was my understanding too, but then [1] called that into question. If -- and I don't really have enough expertise to verify that "if" -- the reason OpenSSL is slower isn't because of "entropy", but because of operations and safety checks that it has to ask the kernel to make for it, then it stands to reason that the kernel could do that a lot faster. If it turns out that's not the case (the post at [1] is ten years old; things change, or Adam could have been wrong, or...), I think that getentropy() is still a straight upgrade from /dev/urandom, due to its increased safety guarantees at startup. > If we make that configurable, documentation sounds like the > key point to me, to explain which one has more benefits over the > other. Agreed. > Could getentropy() be more efficient at the end on most platforms, > meaning that this could limit the meaning of having a GUC switch? I don't know. [2] implies that the performance comparison depends on several factors, and falls in favor of OpenSSL when the number of bytes per call is large -- but our use of pg_strong_random() is generally on small buffers. We would need to do a _lot_ more research before, say, switching any defaults. Thanks, --Jacob [1] https://www.imperialviolet.org/2015/10/17/boringssl.html [2] https://dotat.at/@/2024-10-01-getentropy.html
Jacob Champion <jacob.champion@enterprisedb.com> writes: > On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote: > >> Could getentropy() be more efficient at the end on most platforms, >> meaning that this could limit the meaning of having a GUC switch? > > I don't know. [2] implies that the performance comparison depends on > several factors, and falls in favor of OpenSSL when the number of > bytes per call is large [...] > [2] https://dotat.at/@/2024-10-01-getentropy.html Note that that test was done on an older Linux kernel without the vDSO implementation of getentropy(), so on newer kernel (>=6.11) and glibc (>= 2.41) versions the difference might be smaller or the other way around. - ilmari
On Tue, Jul 29, 2025 at 8:55 AM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote: > > My understanding of the problem is that it is a choice of efficiency > > vs entropy, and that it's not really possible to have both parts of > > the cake. Agreed. I think the optimal choice would depend on the specific use case. For instance, since UUIDs are not intended for security purposes, they don't require particularly high entropy. In UUID generation, the efficiency of random data generation tends to be prioritized over the quality of randomness. > > > Could getentropy() be more efficient at the end on most platforms, > > meaning that this could limit the meaning of having a GUC switch? > > I don't know. [2] implies that the performance comparison depends on > several factors, and falls in favor of OpenSSL when the number of > bytes per call is large -- but our use of pg_strong_random() is > generally on small buffers. We would need to do a _lot_ more research > before, say, switching any defaults. The performance issue with getentropy, particularly when len=1024, likely stems from the need for multiple getentropy() calls due to its 256-byte length restriction. Analysis of RAND_bytes() through strace reveals that it internally makes calls to getrandom() with a fixed length of 32 bytes. While I'm uncertain of the exact purpose, it's logical that a single getentropy() call would be more efficient than RAND_bytes(), which involves additional overhead beyond just calling getrandom(), especially when dealing with smaller byte sizes. I've updated the patch to support getentropy() instead of getrandom(). Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
Вложения
On 22.07.25 13:11, Dagfinn Ilmari Mannsåker wrote: > getrandom() is Linux-specific, while getentropy() is specified by POSIX > (since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and > was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in > 2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024 > > Sources: > > https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html > https://dotat.at/@/2024-10-01-getentropy.html > > So I think it's more worthwhile to add support for getentropy() than > getrandom(). The POSIX description of getentropy() says: "The intended use of this function is to create a seed for other pseudo-random number generators." So using getentropy() for generating the random numbers that are passed back to the application code would appear to be the wrong use.
On 30.07.25 08:59, Masahiko Sawada wrote: > I've updated the patch to support getentropy() instead of getrandom(). The point still stands that the number of installations without OpenSSL support is approximately zero, so what is the purpose of this patch if approximately no one will be able to use it?
Masahiko Sawada <sawada.mshk@gmail.com> writes: > On Tue, Jul 29, 2025 at 8:55 AM Jacob Champion > <jacob.champion@enterprisedb.com> wrote: >> >> On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote: >> > My understanding of the problem is that it is a choice of efficiency >> > vs entropy, and that it's not really possible to have both parts of >> > the cake. > > Agreed. I think the optimal choice would depend on the specific use > case. For instance, since UUIDs are not intended for security > purposes, they don't require particularly high entropy. In UUID > generation, the efficiency of random data generation tends to be > prioritized over the quality of randomness. > >> >> > Could getentropy() be more efficient at the end on most platforms, >> > meaning that this could limit the meaning of having a GUC switch? >> >> I don't know. [2] implies that the performance comparison depends on >> several factors, and falls in favor of OpenSSL when the number of >> bytes per call is large -- but our use of pg_strong_random() is >> generally on small buffers. We would need to do a _lot_ more research >> before, say, switching any defaults. > > The performance issue with getentropy, particularly when len=1024, > likely stems from the need for multiple getentropy() calls due to its > 256-byte length restriction. > > Analysis of RAND_bytes() through strace reveals that it internally > makes calls to getrandom() with a fixed length of 32 bytes. While I'm > uncertain of the exact purpose, it's logical that a single > getentropy() call would be more efficient than RAND_bytes(), which > involves additional overhead beyond just calling getrandom(), > especially when dealing with smaller byte sizes. > > I've updated the patch to support getentropy() instead of getrandom(). Thanks, just a few comments: The blog post at https://dotat.at/@/2024-10-01-getentropy.html#portability-of-getentropy- points out a couple of caveats: * Originally getentropy() was declared in <sys/random.h> but POSIX declares it in <unistd.h>. You need to include both headers to be sure. So the probes need to include both <sys/random.h> (if avaliable) and <unistd.h>, and in the code <sys/random.h> should only be included if available. * POSIX specifies a GETENTROPY_MAX macro in <limits.h> for the largest buffer getentropy() will fill. Most systems don’t yet have this macro; if it isn’t defined the limit is 256 bytes. And this means we should include <limits.h> and only define GETENTROPY_MAX to 256 if it's not already defined. > +bool > +pg_strong_random(void *buf, size_t len) > +{ > + char *p = buf; > + ssize_t res; > + > + while (len) > + { > + size_t l = Min(len, GETENTROPY_MAX_LEN); > + > + res = getentropy(buf, l); This should be getentropy(p, l), otherwise it will will just fill the first GETENTROPY_MAX_LEN bytes of buf repeatedly. On my machine I got a warning about that: ../postgresql/src/port/pg_strong_random.c:159:11: warning: variable 'p' set but not used [-Wunused-but-set-variable] 159 | char *p = buf; | ^ Do we not have any tests for pg_strong_random that make sure it fills the entire bufffer for various sizes? I've attached an updated patch for the above, except I don't know enough autoconf/m4 to make it include <unistd.h> and optionally <sys/random.h> in the check there. - ilmari From 05a53fe6ab33cfa9d6673ee8b868ce66b349e35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org> Date: Wed, 30 Jul 2025 12:36:46 +0100 Subject: [PATCH v3] Support getentropy() as source of pg_strong_random() where available --- configure | 24 ++++++++++++++++++- configure.ac | 8 ++++++- meson.build | 9 ++++++++ src/include/pg_config.h.in | 6 +++++ src/port/pg_strong_random.c | 46 ++++++++++++++++++++++++++++++++++--- 5 files changed, 88 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 507a2437c33..f11cd4265bf 100755 --- a/configure +++ b/configure @@ -16243,6 +16243,25 @@ cat >>confdefs.h <<_ACEOF _ACEOF +ac_fn_c_check_header_mongrel "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_random_h" = xyes; then : + for ac_func in getentropy +do : + ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" +if test "x$ac_cv_func_getentropy" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETENTROPY 1 +_ACEOF + +$as_echo "#define HAVE_GETENTROPY 1" >>confdefs.h + +fi +done + +fi + + + ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes; then : $as_echo "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h @@ -18479,6 +18498,9 @@ $as_echo "Windows native" >&6; } elif test x"$cross_compiling" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5 $as_echo "assuming /dev/urandom" >&6; } +elif test x"$ac_cv_func_getentropy" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: getentropy" >&5 +$as_echo "getentropy" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5 $as_echo "/dev/urandom" >&6; } @@ -18505,7 +18527,7 @@ fi if test x"$ac_cv_file__dev_urandom" = x"no" ; then as_fn_error $? " no source of strong random numbers was found -PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers." "$LINENO" 5 +PostgreSQL can use OpenSSL, native Windows API, getentropy function, or /dev/urandom as a source of random numbers." "$LINENO"5 fi fi diff --git a/configure.ac b/configure.ac index 5f4548adc5c..9cf453fcd23 100644 --- a/configure.ac +++ b/configure.ac @@ -1850,6 +1850,10 @@ AC_CHECK_DECLS([memset_s], [], [], [#define __STDC_WANT_LIB_EXT1__ 1 # This is probably only present on macOS, but may as well check always AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include <fcntl.h>]) +AC_CHECK_HEADER([sys/random.h], + [AC_CHECK_FUNCS([getentropy], + [AC_DEFINE(HAVE_GETENTROPY, 1, [Define to 1 if you have getentropy])])]) + AC_REPLACE_FUNCS(m4_normalize([ explicit_bzero getopt @@ -2314,6 +2318,8 @@ elif test x"$PORTNAME" = x"win32" ; then AC_MSG_RESULT([Windows native]) elif test x"$cross_compiling" = x"yes"; then AC_MSG_RESULT([assuming /dev/urandom]) +elif test x"$ac_cv_func_getentropy" = x"yes"; then + AC_MSG_RESULT(getentropy) else AC_MSG_RESULT([/dev/urandom]) AC_CHECK_FILE([/dev/urandom], [], []) @@ -2321,7 +2327,7 @@ else if test x"$ac_cv_file__dev_urandom" = x"no" ; then AC_MSG_ERROR([ no source of strong random numbers was found -PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers.]) +PostgreSQL can use OpenSSL, native Windows API, getentropy function, or /dev/urandom as a source of random numbers.]) fi fi diff --git a/meson.build b/meson.build index ca423dc8e12..b422b623db1 100644 --- a/meson.build +++ b/meson.build @@ -2627,6 +2627,7 @@ header_checks = [ 'sys/personality.h', 'sys/prctl.h', 'sys/procctl.h', + 'sys/random.h', 'sys/signalfd.h', 'sys/ucred.h', 'termios.h', @@ -2705,6 +2706,14 @@ return 0; don't.'''.format(func)) endforeach +if cc.has_function('getentropy', + args: test_c_args, + prefix: ''' +#include <unistd.h> +@0@ +'''.format(cdata.get('HAVE_SYS_RANDOM_H') == 1 ? '#include <sys/random.h>' : '')) + cdata.set('HAVE_GETENTROPY', 1) +endif if cc.has_type('struct option', args: test_c_args, include_directories: postgres_inc, diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index c4dc5d72bdb..147ab293518 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -172,6 +172,9 @@ /* Define to 1 if you have the `getauxval' function. */ #undef HAVE_GETAUXVAL +/* Define to 1 if you have getentropy */ +#undef HAVE_GETENTROPY + /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS @@ -448,6 +451,9 @@ /* Define to 1 if you have the <sys/procctl.h> header file. */ #undef HAVE_SYS_PROCCTL_H +/* Define to 1 if you have the <sys/random.h> header file. */ +#undef HAVE_SYS_RANDOM_H + /* Define to 1 if you have the <sys/signalfd.h> header file. */ #undef HAVE_SYS_SIGNALFD_H diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index ea6780dcc9f..da482e96ae7 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -40,7 +40,8 @@ * * 1. OpenSSL's RAND_bytes() * 2. Windows' CryptGenRandom() function - * 3. /dev/urandom + * 3. getentropy() function + * 4. /dev/urandom * * Returns true on success, and false if none of the sources * were available. NB: It is important to check the return value! @@ -134,10 +135,49 @@ pg_strong_random(void *buf, size_t len) return false; } -#else /* not USE_OPENSSL or WIN32 */ +#elif HAVE_GETENTROPY + +#include <limits.h> + +#ifdef HAVE_SYS_RANDOM_H +#include <sys/random.h> +#endif + +#ifndef GETENTROPY_MAX +#define GETENTROPY_MAX 256 +#endif + +void +pg_strong_random_init(void) +{ + /* No initialization needed */ +} + +bool +pg_strong_random(void *buf, size_t len) +{ + char *p = buf; + ssize_t res; + + while (len) + { + size_t l = Min(len, GETENTROPY_MAX); + + res = getentropy(p, l); + if (res < 0) + return false; + + p += l; + len -= l; + } + + return true; +} + +#else /* not USE_OPENSSL, WIN32, or HAVE_GETENTROPY */ /* - * Without OpenSSL or Win32 support, just read /dev/urandom ourselves. + * Without OpenSSL, Win32, or getentropy() support, just read /dev/urandom ourselves. */ void -- 2.50.1
> On 30 Jul 2025, at 13:10, Peter Eisentraut <peter@eisentraut.org> wrote: > > On 30.07.25 08:59, Masahiko Sawada wrote: >> I've updated the patch to support getentropy() instead of getrandom(). > > The point still stands that the number of installations without OpenSSL support is approximately zero, so what is the purposeof this patch if approximately no one will be able to use it? The main usecase I've heard discussed (mostly in hallway tracks IIRC) is to allow multiple PRNG's so that codepaths which favor performance over cryptographic properties can choose, this would not be that but a small step on that path (whether or not that's the appropriate step is debatable). For installations without OpenSSL, getrandom() as an API over /dev/urandom still works when /dev is chrooted away. That subset might be too small to spend code on though. -- Daniel Gustafsson
Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> writes: > Masahiko Sawada <sawada.mshk@gmail.com> writes: > >> On Tue, Jul 29, 2025 at 8:55 AM Jacob Champion >> <jacob.champion@enterprisedb.com> wrote: >>> >>> On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote: >>> > My understanding of the problem is that it is a choice of efficiency >>> > vs entropy, and that it's not really possible to have both parts of >>> > the cake. >> >> Agreed. I think the optimal choice would depend on the specific use >> case. For instance, since UUIDs are not intended for security >> purposes, they don't require particularly high entropy. In UUID >> generation, the efficiency of random data generation tends to be >> prioritized over the quality of randomness. >> >>> >>> > Could getentropy() be more efficient at the end on most platforms, >>> > meaning that this could limit the meaning of having a GUC switch? >>> >>> I don't know. [2] implies that the performance comparison depends on >>> several factors, and falls in favor of OpenSSL when the number of >>> bytes per call is large -- but our use of pg_strong_random() is >>> generally on small buffers. We would need to do a _lot_ more research >>> before, say, switching any defaults. >> >> The performance issue with getentropy, particularly when len=1024, >> likely stems from the need for multiple getentropy() calls due to its >> 256-byte length restriction. >> >> Analysis of RAND_bytes() through strace reveals that it internally >> makes calls to getrandom() with a fixed length of 32 bytes. While I'm >> uncertain of the exact purpose, it's logical that a single >> getentropy() call would be more efficient than RAND_bytes(), which >> involves additional overhead beyond just calling getrandom(), >> especially when dealing with smaller byte sizes. >> >> I've updated the patch to support getentropy() instead of getrandom(). > > Thanks, just a few comments: > > The blog post at > https://dotat.at/@/2024-10-01-getentropy.html#portability-of-getentropy- > points out a couple of caveats: > > * Originally getentropy() was declared in <sys/random.h> but POSIX > declares it in <unistd.h>. You need to include both headers to be > sure. > > So the probes need to include both <sys/random.h> (if avaliable) and > <unistd.h>, I realised I got the conditional for this wrong, since cdata.get('HAVE_SYS_RANDOM_H') can return either the integer 1 or the boolean false, so it needs to be format()-ed and compared to a string. Updated patch attached. - ilmari From 88b155c691806bd116b001334cad8ffc1f43e741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org> Date: Wed, 30 Jul 2025 12:36:46 +0100 Subject: [PATCH v4] Support getentropy() as source of pg_strong_random() where available --- configure | 24 ++++++++++++++++++- configure.ac | 8 ++++++- meson.build | 9 ++++++++ src/include/pg_config.h.in | 6 +++++ src/port/pg_strong_random.c | 46 ++++++++++++++++++++++++++++++++++--- 5 files changed, 88 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 507a2437c33..f11cd4265bf 100755 --- a/configure +++ b/configure @@ -16243,6 +16243,25 @@ cat >>confdefs.h <<_ACEOF _ACEOF +ac_fn_c_check_header_mongrel "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_random_h" = xyes; then : + for ac_func in getentropy +do : + ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" +if test "x$ac_cv_func_getentropy" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETENTROPY 1 +_ACEOF + +$as_echo "#define HAVE_GETENTROPY 1" >>confdefs.h + +fi +done + +fi + + + ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes; then : $as_echo "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h @@ -18479,6 +18498,9 @@ $as_echo "Windows native" >&6; } elif test x"$cross_compiling" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5 $as_echo "assuming /dev/urandom" >&6; } +elif test x"$ac_cv_func_getentropy" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: getentropy" >&5 +$as_echo "getentropy" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5 $as_echo "/dev/urandom" >&6; } @@ -18505,7 +18527,7 @@ fi if test x"$ac_cv_file__dev_urandom" = x"no" ; then as_fn_error $? " no source of strong random numbers was found -PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers." "$LINENO" 5 +PostgreSQL can use OpenSSL, native Windows API, getentropy function, or /dev/urandom as a source of random numbers." "$LINENO"5 fi fi diff --git a/configure.ac b/configure.ac index 5f4548adc5c..9cf453fcd23 100644 --- a/configure.ac +++ b/configure.ac @@ -1850,6 +1850,10 @@ AC_CHECK_DECLS([memset_s], [], [], [#define __STDC_WANT_LIB_EXT1__ 1 # This is probably only present on macOS, but may as well check always AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include <fcntl.h>]) +AC_CHECK_HEADER([sys/random.h], + [AC_CHECK_FUNCS([getentropy], + [AC_DEFINE(HAVE_GETENTROPY, 1, [Define to 1 if you have getentropy])])]) + AC_REPLACE_FUNCS(m4_normalize([ explicit_bzero getopt @@ -2314,6 +2318,8 @@ elif test x"$PORTNAME" = x"win32" ; then AC_MSG_RESULT([Windows native]) elif test x"$cross_compiling" = x"yes"; then AC_MSG_RESULT([assuming /dev/urandom]) +elif test x"$ac_cv_func_getentropy" = x"yes"; then + AC_MSG_RESULT(getentropy) else AC_MSG_RESULT([/dev/urandom]) AC_CHECK_FILE([/dev/urandom], [], []) @@ -2321,7 +2327,7 @@ else if test x"$ac_cv_file__dev_urandom" = x"no" ; then AC_MSG_ERROR([ no source of strong random numbers was found -PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers.]) +PostgreSQL can use OpenSSL, native Windows API, getentropy function, or /dev/urandom as a source of random numbers.]) fi fi diff --git a/meson.build b/meson.build index ca423dc8e12..70f5d6494cb 100644 --- a/meson.build +++ b/meson.build @@ -2627,6 +2627,7 @@ header_checks = [ 'sys/personality.h', 'sys/prctl.h', 'sys/procctl.h', + 'sys/random.h', 'sys/signalfd.h', 'sys/ucred.h', 'termios.h', @@ -2705,6 +2706,14 @@ return 0; don't.'''.format(func)) endforeach +if cc.has_function('getentropy', + args: test_c_args, + prefix: ''' +#include <unistd.h> +@0@ +'''.format('@0@'.format(cdata.get('HAVE_SYS_RANDOM_H')) == '1' ? '#include <sys/random.h>' : '')) + cdata.set('HAVE_GETENTROPY', 1) +endif if cc.has_type('struct option', args: test_c_args, include_directories: postgres_inc, diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index c4dc5d72bdb..147ab293518 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -172,6 +172,9 @@ /* Define to 1 if you have the `getauxval' function. */ #undef HAVE_GETAUXVAL +/* Define to 1 if you have getentropy */ +#undef HAVE_GETENTROPY + /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS @@ -448,6 +451,9 @@ /* Define to 1 if you have the <sys/procctl.h> header file. */ #undef HAVE_SYS_PROCCTL_H +/* Define to 1 if you have the <sys/random.h> header file. */ +#undef HAVE_SYS_RANDOM_H + /* Define to 1 if you have the <sys/signalfd.h> header file. */ #undef HAVE_SYS_SIGNALFD_H diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index ea6780dcc9f..da482e96ae7 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -40,7 +40,8 @@ * * 1. OpenSSL's RAND_bytes() * 2. Windows' CryptGenRandom() function - * 3. /dev/urandom + * 3. getentropy() function + * 4. /dev/urandom * * Returns true on success, and false if none of the sources * were available. NB: It is important to check the return value! @@ -134,10 +135,49 @@ pg_strong_random(void *buf, size_t len) return false; } -#else /* not USE_OPENSSL or WIN32 */ +#elif HAVE_GETENTROPY + +#include <limits.h> + +#ifdef HAVE_SYS_RANDOM_H +#include <sys/random.h> +#endif + +#ifndef GETENTROPY_MAX +#define GETENTROPY_MAX 256 +#endif + +void +pg_strong_random_init(void) +{ + /* No initialization needed */ +} + +bool +pg_strong_random(void *buf, size_t len) +{ + char *p = buf; + ssize_t res; + + while (len) + { + size_t l = Min(len, GETENTROPY_MAX); + + res = getentropy(p, l); + if (res < 0) + return false; + + p += l; + len -= l; + } + + return true; +} + +#else /* not USE_OPENSSL, WIN32, or HAVE_GETENTROPY */ /* - * Without OpenSSL or Win32 support, just read /dev/urandom ourselves. + * Without OpenSSL, Win32, or getentropy() support, just read /dev/urandom ourselves. */ void -- 2.50.1
On 30.07.25 13:55, Daniel Gustafsson wrote: >> The point still stands that the number of installations without OpenSSL support is approximately zero, so what is thepurpose of this patch if approximately no one will be able to use it? > The main usecase I've heard discussed (mostly in hallway tracks IIRC) is to > allow multiple PRNG's so that codepaths which favor performance over > cryptographic properties can choose, this would not be that but a small step on > that path (whether or not that's the appropriate step is debatable). This sounds like a reasonable goal. Intuitively, you want stronger randomness for hashing a password than for generating UUIDs. Then again, it's not clear how much stronger exactly. RFC 9562 does call for "cryptographically secure" random numbers. Do we want multiple levels of "strong" or "secure"? This needs a lot more analysis.
On Wed, Jul 30, 2025 at 4:09 AM Peter Eisentraut <peter@eisentraut.org> wrote: > The POSIX description of getentropy() says: > > "The intended use of this function is to create a seed for other > pseudo-random number generators." > > So using getentropy() for generating the random numbers that are passed > back to the application code would appear to be the wrong use. What are the situations in which a stream of numbers would be suitable for seeding a CSPRNG, but not suitable as output from a CSPRNG? On Wed, Jul 30, 2025 at 4:10 AM Peter Eisentraut <peter@eisentraut.org> wrote: > The point still stands that the number of installations without OpenSSL > support is approximately zero, so what is the purpose of this patch if > approximately no one will be able to use it? Upthread I'd suggested that we put some thought into making it configurable, with the understanding that we'd need to document exactly what we think the advantages of the approaches are. --Jacob
On 30.07.25 18:13, Jacob Champion wrote: > On Wed, Jul 30, 2025 at 4:09 AM Peter Eisentraut<peter@eisentraut.org> wrote: >> The POSIX description of getentropy() says: >> >> "The intended use of this function is to create a seed for other >> pseudo-random number generators." >> >> So using getentropy() for generating the random numbers that are passed >> back to the application code would appear to be the wrong use. > What are the situations in which a stream of numbers would be suitable > for seeding a CSPRNG, but not suitable as output from a CSPRNG? I imagine a "get entropy" operation could be very slow or even blocking, whereas a random number generator might just have to do some arithmetic starting from the previous seed state. I mean, they called it "get entropy", not "get random", for a reason?
On Wed, Jul 30, 2025 at 12:58 PM Peter Eisentraut <peter@eisentraut.org> wrote: > I imagine a "get entropy" operation could be very slow or even blocking, > whereas a random number generator might just have to do some arithmetic > starting from the previous seed state. Agreed -- it could absolutely be slower, but if it's not slower in practice in a user's environment, is there a problem with using it as the basis for pg_strong_random()? That doesn't seem "wrong" to me; it just seems like a tradeoff that would take investigation. (The "blocking" fear is related to the research I linked above -- we don't really want our CSPRNG to block in the way that /dev/random used to, because that's not helpful. But we absolutely want it to block if the CSPRNG state hasn't initialized yet. The goal continues to be strength over performance IMO -- but there is circumstantial evidence here that getentropy() could maybe get us both, in some environments.) --Jacob
On Wed, Jul 30, 2025 at 02:03:53PM -0700, Jacob Champion wrote: > On Wed, Jul 30, 2025 at 12:58 PM Peter Eisentraut <peter@eisentraut.org> wrote: > > I imagine a "get entropy" operation could be very slow or even blocking, > > whereas a random number generator might just have to do some arithmetic > > starting from the previous seed state. > > Agreed -- it could absolutely be slower, but if it's not slower in > practice in a user's environment, is there a problem with using it as > the basis for pg_strong_random()? That doesn't seem "wrong" to me; it > just seems like a tradeoff that would take investigation. Yeah, we need to be careful here. Having a blocking or less efficient operation would be bad for the UUID generation, especially in INSERT-only workloads and there are a lot of such things these days that also want to maintain some uniqueness of the data gathered across multiple nodes. I'm questioning whether the UUID generation could become a bottleneck if we are not careful, showing high in profiles. -- Michael
Вложения
On Wed, Jul 30, 2025 at 2:04 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Wed, Jul 30, 2025 at 12:58 PM Peter Eisentraut <peter@eisentraut.org> wrote: > > I imagine a "get entropy" operation could be very slow or even blocking, > > whereas a random number generator might just have to do some arithmetic > > starting from the previous seed state. > > Agreed -- it could absolutely be slower, but if it's not slower in > practice in a user's environment, is there a problem with using it as > the basis for pg_strong_random()? That doesn't seem "wrong" to me; it > just seems like a tradeoff that would take investigation. Regarding glibc's getrandom() and getentropy() implementation[1], getentropy() seems to be implemented as a wrapper of getrandom() in a sense. That is, getrandom() has more fine grained control such as specifying blocking behavior and the source (/dev/random or /dev/urandom). glibc's getentropy() simply calls getrandom() with flag=0 and 256 byte limitation. I think there is no difference between random bytes generated by getrandom() and getentropy() in strength. And according Linux manual for getentropy(), A call to getentropy() may block if the system has just booted and the kernel has not yet collected enough randomness to initialize the entropy pool. Which is the same behavior of calling getrandom() without GRND_NONBLOCK. I believe FreeBSD's getentropy() is almost the same; it internally calls getrandom()[2]. On the other hand, I found a blog post[3] (10 years-old post) that on Solaris the output of getentropy() should not be used where randomness is needed. I'm not sure it's still true but I guess that it might be reasonable to consider that this is correct behavior in principle, and that the behavior of glibc etc. is in some sense an exception. Regards, [1] https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getentropy.c;h=a62c9fb09962d4918a9c8cdd5545ad803b62fb82;hb=d2097651cc57834dbfcaa102ddfacae0d86cfb66 [2] https://github.com/freebsd/freebsd-src/blob/main/lib/libc/gen/getentropy.c [3] https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2 -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Fri, Aug 8, 2025 at 3:25 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > On the other hand, I found a blog post[3] (10 years-old post) that on > Solaris the output of getentropy() should not be used where randomness > is needed. I'm not sure it's still true but I guess that it might be > reasonable to consider that this is correct behavior in principle, and > that the behavior of glibc etc. is in some sense an exception. Thanks for finding that! Ah, FIPS: > More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG appliedto it. So FIPS compliance is a case where "a stream of numbers would be suitable for seeding a CSPRNG, but not suitable as output from a CSPRNG". That's evidence enough for me to abandon my preference for getentropy() (whether Solaris still does that or not). I've been looking at libsodium's randomness implementations [1]: > On Windows systems, the RtlGenRandom() function is used. > On OpenBSD and Bitrig, the arc4random() function is used. > On recent FreeBSD and Linux kernels, the getrandom system call is used. > On other Unices, the /dev/urandom device is used. (Note that libsodium has some internal concept of a "safe" arc4random implementation, which it locks to certain platforms. If an OS is still literally using RC4 we would not want to use it.) So, my next question: is getrandom() always preferable to /dev/urandom? --Jacob [1] https://doc.libsodium.org/generating_random_data
On Tue, Jul 29, 2025 at 9:38 AM Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> wrote: > > Jacob Champion <jacob.champion@enterprisedb.com> writes: > > > On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote: > > > >> Could getentropy() be more efficient at the end on most platforms, > >> meaning that this could limit the meaning of having a GUC switch? > > > > I don't know. [2] implies that the performance comparison depends on > > several factors, and falls in favor of OpenSSL when the number of > > bytes per call is large > [...] > > [2] https://dotat.at/@/2024-10-01-getentropy.html > > Note that that test was done on an older Linux kernel without the vDSO > implementation of getentropy(), so on newer kernel (>=6.11) and glibc > (>= 2.41) versions the difference might be smaller or the other way > around. FYI I've benchmarked vDSO implementation of getrandom() with Fedora 42 (kernel 6.15, glibc 2.41). I've modified the test program linked by the blog post[1] so that it measures vDSO implementation of getrandom() and directly calling getrandom system call. I've attached the test program. Here is the result: $ ./bench init openssl 1929533 len entropy openssl vgetrandom getrandom 16 353 400 39 235 64 373 401 125 368 256 675 420 432 664 1024 2651 494 1352 1792 The 'vgetrandom' column shows nanoseconds per function call of vDSO implementation of getrandom() function whereas the 'getrandom' column shows nanoseconds per getrandom system call. For smaller bytes, vgetrandom (i.e., simply calling the getrandom() function) is much faster than other methods. For larger bytes (such 1024), openssl had the best performance. This fact is very attractive to me in terms of using it for UUID generation. Regards, [1] https://dotat.at/@/2024-10-01-getentropy.html -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
Вложения
On Fri, Aug 8, 2025 at 3:37 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Fri, Aug 8, 2025 at 3:25 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > On the other hand, I found a blog post[3] (10 years-old post) that on > > Solaris the output of getentropy() should not be used where randomness > > is needed. I'm not sure it's still true but I guess that it might be > > reasonable to consider that this is correct behavior in principle, and > > that the behavior of glibc etc. is in some sense an exception. > > Thanks for finding that! Ah, FIPS: > > > More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG appliedto it. > > So FIPS compliance is a case where "a stream of numbers would be > suitable for seeding a CSPRNG, but not suitable as output from a > CSPRNG". That's evidence enough for me to abandon my preference for > getentropy() (whether Solaris still does that or not). Makes sense. > > I've been looking at libsodium's randomness implementations [1]: > > > On Windows systems, the RtlGenRandom() function is used. > > On OpenBSD and Bitrig, the arc4random() function is used. > > On recent FreeBSD and Linux kernels, the getrandom system call is used. > > On other Unices, the /dev/urandom device is used. > > (Note that libsodium has some internal concept of a "safe" arc4random > implementation, which it locks to certain platforms. If an OS is still > literally using RC4 we would not want to use it.) > > So, my next question: is getrandom() always preferable to /dev/urandom? I believe so. While /dev/urandom source should be kept as a fallback for older kernels, we should use getrandom() if available. For example, getrandom() can be used even in the face of file-descriptor exhaustion and lack of access to the random devices[1]. Also, it would be much faster than reading /dev/urandom as I shared the benchmark result[2]. Regards, [1] https://lwn.net/Articles/884875/ [2] https://www.postgresql.org/message-id/CAD21AoD1%2B6FwGb0d4W3YEwOVJi_McuyuvpnjUJE8B8Ejy21MMw%40mail.gmail.com -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Thu, Aug 14, 2025 at 3:16 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > On Fri, Aug 8, 2025 at 3:37 PM Jacob Champion > <jacob.champion@enterprisedb.com> wrote: > > > So, my next question: is getrandom() always preferable to /dev/urandom? > > I believe so. While /dev/urandom source should be kept as a fallback > for older kernels, we should use getrandom() if available. For > example, getrandom() can be used even in the face of file-descriptor > exhaustion and lack of access to the random devices[1]. Also, it would > be much faster than reading /dev/urandom as I shared the benchmark > result[2]. Yeah. My personal reasons to be excited about it are 1) the newer, more sensible one-shot blocking behavior for safety, and 2) the ability for the OS to figure out when a virtualized environment has potentially "forked" So I think I would be in favor of adding this as an always-preferred alternative to /dev/urandom, to begin. Thinking a bit further ahead: what are some criteria we would need to research to decide whether getrandom() would be preferable to OpenSSL? Gathering a couple of considerations from upthread: - FIPS behavior - Speed vs. size of a "typical" request - Version-specific behavior of OpenSSL and/or the OS - Need for safety in virtualized environments - ...? Thanks, --Jacob
On Mon, Aug 18, 2025 at 08:38:25AM -0700, Jacob Champion wrote: > - Need for safety in virtualized environments > - ...? Interesting. What do you mean by this point? Isolation of the random computations on a VM/container basis even if these are originally from the same host? -- Michael
Вложения
On Mon, Aug 18, 2025 at 4:17 PM Michael Paquier <michael@paquier.xyz> wrote: > > On Mon, Aug 18, 2025 at 08:38:25AM -0700, Jacob Champion wrote: > > - Need for safety in virtualized environments > > - ...? > > Interesting. What do you mean by this point? Isolation of the > random computations on a VM/container basis even if these are > originally from the same host? One motivating example is "I paused my VM and cloned it and now both application instances are giving me the same random numbers." (I haven't looked into OpenSSL enough to know if it has developed some magic way around this, for the record.) NetBSD talks about this a bit at [1]. I'd imagine that there are other nice things about moving it down into the kernel, like core dumps becoming ever so slightly less dangerous? But that's pretty out there. --Jacob [1] https://man.netbsd.org/acpivmgenid.4
On Mon, Aug 18, 2025 at 8:38 AM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Thu, Aug 14, 2025 at 3:16 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > On Fri, Aug 8, 2025 at 3:37 PM Jacob Champion > > <jacob.champion@enterprisedb.com> wrote: > > > > > So, my next question: is getrandom() always preferable to /dev/urandom? > > > > I believe so. While /dev/urandom source should be kept as a fallback > > for older kernels, we should use getrandom() if available. For > > example, getrandom() can be used even in the face of file-descriptor > > exhaustion and lack of access to the random devices[1]. Also, it would > > be much faster than reading /dev/urandom as I shared the benchmark > > result[2]. > > Yeah. My personal reasons to be excited about it are > 1) the newer, more sensible one-shot blocking behavior for safety, and > 2) the ability for the OS to figure out when a virtualized environment > has potentially "forked" > > So I think I would be in favor of adding this as an always-preferred > alternative to /dev/urandom, to begin. > > Thinking a bit further ahead: what are some criteria we would need to > research to decide whether getrandom() would be preferable to OpenSSL? > Gathering a couple of considerations from upthread: > - FIPS behavior Do you mean random numbers generated by getrandom() complaints FIPS? Based on my research, there doesn't appear to be any explicit statement indicating that Linux's CSPRNG module complies with FIPS requirements. However, there is a proposal to implement LRNG[1], which would be FIPS-compliant. In systems that require FIPS compliance, it seems that random numbers generated by getrandom() (or getentropy()) are typically used as a seed for FIPS-compliant random number generators, such as OpenSSL's RAND_bytes() function. Regards, [1] https://lwn.net/Articles/877607/ -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Mon, Aug 25, 2025 at 11:30 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > Gathering a couple of considerations from upthread: > > - FIPS behavior > > Do you mean random numbers generated by getrandom() complaints FIPS? > Based on my research, there doesn't appear to be any explicit > statement indicating that Linux's CSPRNG module complies with FIPS > requirements. However, there is a proposal to implement LRNG[1], which > would be FIPS-compliant. Right. I guess what I'm asking with that particular bullet point is: If, tomorrow, I threw caution to the wind and proposed that we use getrandom() on Linux over OpenSSL by default, would any FIPS users complain? Or are they all using distributions that have already applied FIPS patches to the getrandom() part of the kernel anyway? (But I intended for that to be a possible future point of discussion, not a blocker for your smaller proposal.) Thanks, --Jacob
On Mon, Aug 25, 2025 at 1:07 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Mon, Aug 25, 2025 at 11:30 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > Gathering a couple of considerations from upthread: > > > - FIPS behavior > > > > Do you mean random numbers generated by getrandom() complaints FIPS? > > Based on my research, there doesn't appear to be any explicit > > statement indicating that Linux's CSPRNG module complies with FIPS > > requirements. However, there is a proposal to implement LRNG[1], which > > would be FIPS-compliant. > > Right. I guess what I'm asking with that particular bullet point is: > > If, tomorrow, I threw caution to the wind and proposed that we use > getrandom() on Linux over OpenSSL by default, would any FIPS users > complain? Or are they all using distributions that have already > applied FIPS patches to the getrandom() part of the kernel anyway? Valid point. I guess the approach of selecting the random number source at compile time might be inflexible, and there does not seem to be a one-size-fits-all solution when it comes to things like this. The fact made me think we could have PostgreSQL select its random number source when it starts up instead of compile time, giving us the flexibility to cater to various scenarios. For instance, we could introduce a GUC parameter that lets users specify their preferred random number source. Or the server can automatically select it based on the kernel's FIPS mode (i.e., checking /proc/sys/crypto/fips_enabled). Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > For instance, we could > introduce a GUC parameter that lets users specify their preferred > random number source. Or the server can automatically select it based > on the kernel's FIPS mode (i.e., checking > /proc/sys/crypto/fips_enabled). Interesting idea. (Are there any users reading along who would definitely use such a feature?) --Jacob
> On 26 Aug 2025, at 00:38, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: >> >> For instance, we could >> introduce a GUC parameter that lets users specify their preferred >> random number source. Or the server can automatically select it based >> on the kernel's FIPS mode (i.e., checking >> /proc/sys/crypto/fips_enabled). > > Interesting idea. (Are there any users reading along who would > definitely use such a feature?) I worry about the added complexity this would bring. It's already quite complicated to configure postgres, and making an informed decision about which RNG source to choose for cryptographically strong random won't be easy without domain knowledge. Taking a step back and re-reading the thread, this started as a proposal to improve uuid generation on non-Windows platforms when not using OpenSSL. While non-SSL installations will be incredibly rare in production, it will likely be a bit more common in PG development situations and speeding up test-runs in such situations has value. I think this thread has shown merit to the idea of replacing using /dev/urandom with a more modern API, but after sleeping on it I'm less convinced that a'la carte CSPRNG configuration has enough upsides to warrant the risk of users accidentally becoming non-FIPS compliant. Another related thing to consider, uuid-ossp contrib module use arc4random() in the non e2fs case. -- Daniel Gustafsson
On Tue, Aug 26, 2025 at 12:42 AM Daniel Gustafsson <daniel@yesql.se> wrote: > > > On 26 Aug 2025, at 00:38, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > > > On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > >> > >> For instance, we could > >> introduce a GUC parameter that lets users specify their preferred > >> random number source. Or the server can automatically select it based > >> on the kernel's FIPS mode (i.e., checking > >> /proc/sys/crypto/fips_enabled). > > > > Interesting idea. (Are there any users reading along who would > > definitely use such a feature?) > > I worry about the added complexity this would bring. It's already quite > complicated to configure postgres, and making an informed decision about which > RNG source to choose for cryptographically strong random won't be easy without > domain knowledge. > > Taking a step back and re-reading the thread, this started as a proposal to > improve uuid generation on non-Windows platforms when not using OpenSSL. While > non-SSL installations will be incredibly rare in production, it will likely be > a bit more common in PG development situations and speeding up test-runs in > such situations has value. I think this thread has shown merit to the idea of > replacing using /dev/urandom with a more modern API, but after sleeping on it > I'm less convinced that a'la carte CSPRNG configuration has enough upsides to > warrant the risk of users accidentally becoming non-FIPS compliant. The primary motivation is to enhance the performance of random data generation and UUID creation in scenarios where FIPS compliance is not mandatory. As I previously reported[1], getrandom() demonstrates superior performance for small random data operations, with the efficiency gain becoming even more significant in newer kernels thanks to the vDSO implementation of getrandom() (note that I assume cryptographic equivalence between random data generated by RAND_bytes() in non-FIPS mode and that produced by getrandom()). Although this would introduce additional configuration complexity, I guess that FIPS-compliant random data is unnecessary for most users, and getrandom()'s output is typically sufficient for many implementations. I think while maintaining RAND_bytes() as the default option for OpenSSL-enabled installations, we could somehow provide users with the flexibility to opt for getrandom() when preferred. > > Another related thing to consider, uuid-ossp contrib module use arc4random() in > the non e2fs case. An alternative approach for users seeking to generate UUIDs via getrandom() would be to utilize UUIDv7 through uuid_generate_time_v7() provided by libuuid in e2fs cases. Since this method internally leverages getrandom(), it should benefit from vDSO execution capabilities. However, we need to note that UUIDv7 values generated through uuid_generate_time_v7() exhibit several distinctions from those produced by PostgreSQL's implementation. Regards, [1] https://www.postgresql.org/message-id/CAD21AoD1%2B6FwGb0d4W3YEwOVJi_McuyuvpnjUJE8B8Ejy21MMw%40mail.gmail.com -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Wed, Aug 27, 2025 at 4:48 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > On Tue, Aug 26, 2025 at 12:42 AM Daniel Gustafsson <daniel@yesql.se> wrote: > > > > > On 26 Aug 2025, at 00:38, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > > > > > On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > >> > > >> For instance, we could > > >> introduce a GUC parameter that lets users specify their preferred > > >> random number source. Or the server can automatically select it based > > >> on the kernel's FIPS mode (i.e., checking > > >> /proc/sys/crypto/fips_enabled). > > > > > > Interesting idea. (Are there any users reading along who would > > > definitely use such a feature?) > > > > I worry about the added complexity this would bring. It's already quite > > complicated to configure postgres, and making an informed decision about which > > RNG source to choose for cryptographically strong random won't be easy without > > domain knowledge. > > > > Taking a step back and re-reading the thread, this started as a proposal to > > improve uuid generation on non-Windows platforms when not using OpenSSL. While > > non-SSL installations will be incredibly rare in production, it will likely be > > a bit more common in PG development situations and speeding up test-runs in > > such situations has value. I think this thread has shown merit to the idea of > > replacing using /dev/urandom with a more modern API, but after sleeping on it > > I'm less convinced that a'la carte CSPRNG configuration has enough upsides to > > warrant the risk of users accidentally becoming non-FIPS compliant. > > The primary motivation is to enhance the performance of random data > generation and UUID creation in scenarios where FIPS compliance is not > mandatory. As I previously reported[1], getrandom() demonstrates > superior performance for small random data operations, with the > efficiency gain becoming even more significant in newer kernels thanks > to the vDSO implementation of getrandom() (note that I assume > cryptographic equivalence between random data generated by > RAND_bytes() in non-FIPS mode and that produced by getrandom()). > > Although this would introduce additional configuration complexity, I > guess that FIPS-compliant random data is unnecessary for most users, > and getrandom()'s output is typically sufficient for many > implementations. I think while maintaining RAND_bytes() as the default > option for OpenSSL-enabled installations, we could somehow provide > users with the flexibility to opt for getrandom() when preferred. I've drafted this idea and attached two patches. The first patch allows the user to select the random source function used in the backend. 'openssl' is the default value if PostgreSQL is built with openssl but users can set it to 'system' use the '/dev/urandom/' approach (or CryptGenRandom on Windows) instead if they want. In frontend code, there is nothing changed; the actual implementation of pg_strong_random is chosed at build time and openssl's RAND_bytes() is always used if the source code is built with openssl. Therefore, it doesn't break any existing use cases but provides a way to select the random source function.The second patch adds support for getrandom() as the default random source of 'system' random source type on Unix-like platforms. With these two patches, for example, users can set random_source_type to 'system' in the configuration file or a connection string in order to use getrandom() for random data generation for UUID generation even on openssl-enabled builds: % echo "show random_source_type; select uuidv7();" | bin/psql -d "dbname=postgres port=5432 options='-c random_source_type=openssl'" -X random_source_type -------------------- openssl (1 row) uuidv7 -------------------------------------- 01997599-b6b6-7590-9825-f36253059956 (1 row) % echo "show random_source_type; select uuidv7();" | bin/psql -d "dbname=postgres port=5432 options='-c random_source_type=system'" -X random_source_type -------------------- system (1 row) uuidv7 -------------------------------------- 01997599-f069-76b6-9ce2-0308d0cd6a0b (1 row) Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
Вложения
On Tue, Sep 23, 2025 at 1:41 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > With these two patches, for example, users can set random_source_type > to 'system' in the configuration file or a connection string in order > to use getrandom() for random data generation for UUID generation even > on openssl-enabled builds: I'm wary of letting unprivileged users switch this implementation. I think our developers should be allowed to treat the user as an adversary when developing features on top of pg_strong_random(), and it doesn't make sense for an adversary to control properties of your CSPRNG. I'm also worried that allowing users to change the FIPS properties of their systems could lead to compliance headaches for some DBAs, but maybe somebody knows a reason why that wouldn't be a concern in practice. But if only a superuser can change this, I'm not sure that it's going to fit your use case anymore. Which probably brings the conversation back to Daniel's note upthread -- is it worth the cost to expose this as a runtime knob? --Jacob
On Mon, Sep 29, 2025 at 03:15:37PM -0700, Jacob Champion wrote: > I'm wary of letting unprivileged users switch this implementation. I > think our developers should be allowed to treat the user as an > adversary when developing features on top of pg_strong_random(), and > it doesn't make sense for an adversary to control properties of your > CSPRNG. I'm also worried that allowing users to change the FIPS > properties of their systems could lead to compliance headaches for > some DBAs, but maybe somebody knows a reason why that wouldn't be a > concern in practice. I'm pretty sure that all cloud vendors would face this dilemma, and another thing that I suspect it that they would restrict entirely the access to this GUC. > But if only a superuser can change this, I'm not sure that it's going > to fit your use case anymore. Which probably brings the conversation > back to Daniel's note upthread -- is it worth the cost to expose this > as a runtime knob? I don't think we should expose that as a runtime-updatable parameter. Even for UUIDs, I am reading the RFC as "more entropy the better" and I would choose entropy over performance every single day, because it's a no brainer if you care about cryptography, especially if this option enforces which source to use for for *all* code paths that want random bytes. So there is no deal about performance here, at least IMHO. Even as a superuser parameter, I'm having cold feet with this prospect. There are two aspects not discussed on this thread that could justify a PGC_POSTMASTER: - Testing, by being able to switch from one source to the other, providing more coverage with external libraries, useful for the buildfarm. - Insurance policy against vendor and library bugs. By switching to a different source with an existing build, it is possible to redirect the source of a bug somewhere else. It was also one of the reasons behind the GUCs that control the SSL protocol versions, where we wanted to bypass some versions. With TLSv3, this is less an issue these days, compared to SSLv1/2, still the argument applied when the SSL protocol GUCs were added. -- Michael
Вложения
On Mon, Sep 29, 2025 at 11:01 PM Michael Paquier <michael@paquier.xyz> wrote: > > On Mon, Sep 29, 2025 at 03:15:37PM -0700, Jacob Champion wrote: > > I'm wary of letting unprivileged users switch this implementation. I > > think our developers should be allowed to treat the user as an > > adversary when developing features on top of pg_strong_random(), and > > it doesn't make sense for an adversary to control properties of your > > CSPRNG. I'm also worried that allowing users to change the FIPS > > properties of their systems could lead to compliance headaches for > > some DBAs, but maybe somebody knows a reason why that wouldn't be a > > concern in practice. > > I'm pretty sure that all cloud vendors would face this dilemma, and > another thing that I suspect it that they would restrict entirely the > access to this GUC. > > > But if only a superuser can change this, I'm not sure that it's going > > to fit your use case anymore. Which probably brings the conversation > > back to Daniel's note upthread -- is it worth the cost to expose this > > as a runtime knob? > > I don't think we should expose that as a runtime-updatable parameter. I agree that it should not be exposed as a runtime parameter. > Even for UUIDs, I am reading the RFC as "more entropy the better" and > I would choose entropy over performance every single day, because it's > a no brainer if you care about cryptography, especially if this option > enforces which source to use for for *all* code paths that want random > bytes. So there is no deal about performance here, at least IMHO. I'm still studying this area but is there any difference in entropy between random numbers generated by getrandom() and OpenSSL's RAND_bytes() in terms of entropy? The RFC says "Implementations SHOULD utilize a cryptographically secure pseudorandom number generator (CSPRNG) to provide values that are both difficult to predict ("unguessable") and have a low likelihood of collision ("unique")." and IIUC getrandom() generates random numbers from the kernel's CSPRNG module. > > Even as a superuser parameter, I'm having cold feet with this > prospect. There are two aspects not discussed on this thread that > could justify a PGC_POSTMASTER: > - Testing, by being able to switch from one source to the other, > providing more coverage with external libraries, useful for the > buildfarm. > - Insurance policy against vendor and library bugs. By switching to a > different source with an existing build, it is possible to redirect > the source of a bug somewhere else. It was also one of the reasons > behind the GUCs that control the SSL protocol versions, where we > wanted to bypass some versions. With TLSv3, this is less an issue > these days, compared to SSLv1/2, still the argument applied when the > SSL protocol GUCs were added. Interesting points. If we can provide a knob as a GUC, I agree that it should be a PGC_POSTMASTER parameter. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
> On 30 Sep 2025, at 00:15, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > I'm wary of letting unprivileged users switch this implementation. I > think our developers should be allowed to treat the user as an > adversary when developing features on top of pg_strong_random(), and > it doesn't make sense for an adversary to control properties of your > CSPRNG. Agreed. > I'm also worried that allowing users to change the FIPS > properties of their systems could lead to compliance headaches for > some DBAs, Very much so. It might not move the needle in practice, but the fact that it could be changed will inevitably lead to a feature request to be able to disable it. I think we're trying to fit two square pegs in the same not-square hole here. While none of the pegs want poor entropy, one (for example UUID generation) favours speed over CSPRNG properties where the other couldn't care less about speed if any CSPRNG properties are even looked at the wrong way on a bad day. What if we instead expand the API to provide pg_random (or pg_fast_random) which can be a selectable implementation, and pg_strong_random is left as today a compile time selection? This would allow extension authors and built-in *non security/auth* features which need to squeeze all the performance they can out of the API to use an alternative implementation while leaving pg_strong_random to give CSPRNG guarantees to code that need it. -- Daniel Gustafsson
On Tue, Sep 30, 2025 at 12:44 AM Daniel Gustafsson <daniel@yesql.se> wrote: > > > On 30 Sep 2025, at 00:15, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > > I'm wary of letting unprivileged users switch this implementation. I > > think our developers should be allowed to treat the user as an > > adversary when developing features on top of pg_strong_random(), and > > it doesn't make sense for an adversary to control properties of your > > CSPRNG. > > Agreed. > > > I'm also worried that allowing users to change the FIPS > > properties of their systems could lead to compliance headaches for > > some DBAs, > > Very much so. It might not move the needle in practice, but the fact that it > could be changed will inevitably lead to a feature request to be able to > disable it. > > > I think we're trying to fit two square pegs in the same not-square hole here. > While none of the pegs want poor entropy, one (for example UUID generation) > favours speed over CSPRNG properties where the other couldn't care less about > speed if any CSPRNG properties are even looked at the wrong way on a bad day. > > What if we instead expand the API to provide pg_random (or pg_fast_random) > which can be a selectable implementation, and pg_strong_random is left as today > a compile time selection? This would allow extension authors and built-in *non > security/auth* features which need to squeeze all the performance they can out > of the API to use an alternative implementation while leaving pg_strong_random > to give CSPRNG guarantees to code that need it. Sounds reasonable. But I have one question: in systems that must be FIPS compliant, is it okay to generate UUIDs using random numbers from non-FIPS compliant sources? If yes, we can use pg_random/pg_fast_random() for UUID generation in all cases. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com