Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build_windows/VS10/db.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@
<ClCompile Include="..\..\src\os\os_aio_iocp.c"/>
<ClCompile Include="..\..\src\os\os_aio_pool.c"/>
<ClCompile Include="..\..\src\os_windows\os_clock.c"/>
<ClCompile Include="..\..\src\os_windows\os_csprng.c"/>
<ClCompile Include="..\..\src\os_windows\os_config.c"/>
<ClCompile Include="..\..\src\os_windows\os_cpu.c"/>
<ClCompile Include="..\..\src\os\os_ctime.c"/>
Expand Down
1 change: 1 addition & 0 deletions build_windows/VS10/db_small.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
<ClCompile Include="..\..\src\os\os_uid.c"/>
<ClCompile Include="..\..\src\os_windows\os_abs.c"/>
<ClCompile Include="..\..\src\os_windows\os_clock.c"/>
<ClCompile Include="..\..\src\os_windows\os_csprng.c"/>
<ClCompile Include="..\..\src\os_windows\os_config.c"/>
<ClCompile Include="..\..\src\os_windows\os_cpu.c"/>
<ClCompile Include="..\..\src\os_windows\os_dir.c"/>
Expand Down
4 changes: 3 additions & 1 deletion dist/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ DTRACE_OBJS= @ADDITIONAL_OBJS@ @REPLACEMENT_OBJS@ @CRYPTO_OBJS@ \
mp_fmethod@o@ mp_fopen@o@ mp_fput@o@ mp_fset@o@ mp_method@o@ \
mp_mvcc@o@ mp_region@o@ mp_register@o@ mp_resize@o@ mp_stat@o@ \
mp_sync@o@ mp_trickle@o@ openflags@o@ os_abort@o@ os_abs@o@ os_aio@o@ os_aio_iocp@o@ os_aio_kqueue@o@ os_aio_pool@o@ os_aio_posix@o@ os_aio_uring@o@ \
os_alloc@o@ os_atomic@o@ os_clock@o@ os_cpu@o@ os_ctime@o@ os_config@o@ \
os_alloc@o@ os_atomic@o@ os_clock@o@ os_cpu@o@ os_csprng@o@ os_ctime@o@ os_config@o@ \
os_dir@o@ os_errno@o@ os_fid@o@ os_flock@o@ os_fsync@o@ \
os_getenv@o@ os_handle@o@ os_map@o@ os_method@o@ os_mkdir@o@ \
os_open@o@ os_path@o@ os_pid@o@ os_rename@o@ os_root@o@ \
Expand Down Expand Up @@ -2705,6 +2705,8 @@ os_clock@o@: $(srcdir)/@OSDIR@/os_clock.c
$(CC) $(CFLAGS) $(DEPFLAGS) $<
os_config@o@: $(srcdir)/@OSDIR@/os_config.c
$(CC) $(CFLAGS) $(DEPFLAGS) $<
os_csprng@o@: $(srcdir)/os/os_csprng.c
$(CC) $(CFLAGS) $(DEPFLAGS) $<
os_cpu@o@: $(srcdir)/@OSDIR@/os_cpu.c
$(CC) $(CFLAGS) $(DEPFLAGS) $<
os_ctime@o@: $(srcdir)/os/os_ctime.c
Expand Down
23 changes: 23 additions & 0 deletions dist/configure
Original file line number Diff line number Diff line change
Expand Up @@ -22094,6 +22094,12 @@ if test "x$ac_cv_header_execinfo_h" = xyes
then :
printf '%s\n' "#define HAVE_EXECINFO_H 1" >>confdefs.h

fi
ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_random_h" = xyes
then :
printf '%s\n' "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h

fi
ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_select_h" = xyes
Expand Down Expand Up @@ -27320,6 +27326,23 @@ then :
fi


# Cryptographically strong OS entropy, used to seed encryption IVs.
# getrandom(2) is Linux/glibc 2.25+; arc4random_buf(3) is the BSDs and macOS.
# Neither is required: os_csprng.c falls back to reading /dev/urandom.
ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom"
if test "x$ac_cv_func_getrandom" = xyes
then :
printf '%s\n' "#define HAVE_GETRANDOM 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "arc4random_buf" "ac_cv_func_arc4random_buf"
if test "x$ac_cv_func_arc4random_buf" = xyes
then :
printf '%s\n' "#define HAVE_ARC4RANDOM_BUF 1" >>confdefs.h

fi




ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
Expand Down
7 changes: 6 additions & 1 deletion dist/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ fi
AC_HEADER_STAT
AC_CHECK_HEADERS([sys/time.h time.h])
AC_HEADER_DIRENT
AC_CHECK_HEADERS(execinfo.h sys/select.h sys/socket.h sys/time.h)
AC_CHECK_HEADERS(execinfo.h sys/random.h sys/select.h sys/socket.h sys/time.h)
AC_CHECK_MEMBERS([struct stat.st_blksize])
AM_TYPES

Expand Down Expand Up @@ -847,6 +847,11 @@ AC_CHECK_FUNCS(\
pthread_self pthread_yield random sched_yield select setgid setuid\
sigaction snprintf stat sysconf vsnprintf yield)

# Cryptographically strong OS entropy, used to seed encryption IVs.
# getrandom(2) is Linux/glibc 2.25+; arc4random_buf(3) is the BSDs and macOS.
# Neither is required: os_csprng.c falls back to reading /dev/urandom.
AC_CHECK_FUNCS(getrandom arc4random_buf)

AC_TIMERS

# Ftruncate.
Expand Down
1 change: 1 addition & 0 deletions dist/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ libdb_srcnames = [
'src/os/os_atomic.c',
'src/os/os_clock.c',
'src/os/os_config.c',
'src/os/os_csprng.c',
'src/os/os_cpu.c',
'src/os/os_ctime.c',
'src/os/os_dir.c',
Expand Down
1 change: 1 addition & 0 deletions dist/srcfiles.in
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ src/os/os_aio_iocp.c android
src/os/os_alloc.c android
src/os/os_clock.c android
src/os/os_config.c android
src/os/os_csprng.c android
src/os/os_cpu.c android
src/os/os_ctime.c android
src/os/os_dir.c android
Expand Down
4 changes: 2 additions & 2 deletions src/common/db_err.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,10 +357,10 @@ db_strerror(error)
return (DB_STR("0088",
"DB_SECONDARY_BAD: Secondary index inconsistent with primary"));
case DB_SNAPSHOT_CONFLICT:
return (DB_STR("4573",
return (DB_STR("0211",
"DB_SNAPSHOT_CONFLICT: Serializable snapshot update conflict"));
case DB_SNAPSHOT_UNSAFE:
return (DB_STR("4574",
return (DB_STR("0212",
"DB_SNAPSHOT_UNSAFE: Potential serializable snapshot anomaly"));
case DB_TIMEOUT:
return (DB_STR("0089", "DB_TIMEOUT: Operation timed out"));
Expand Down
20 changes: 13 additions & 7 deletions src/crypto/mersenne/mt19937db.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,20 @@ __db_genrand(env)

if (env->mti == N+1) { /* if sgenrand() has not been called, */
/*
* Seed the generator with the hashed time. The __db_mac
* function will return 4 bytes if we don't send in a key.
* Seed the generator from the OS entropy source. This used to
* hash the wall-clock seconds, which is low-entropy and
* guessable -- an attacker who knows roughly when the
* environment was created could narrow the IV stream. Fall
* back to the hashed clock only if the OS has no entropy
* source at all, so encryption still functions on such a
* platform (with the historical, weaker seeding).
*/
do {
__os_gettime(env, &ts, 1);
__db_chksum(NULL, (u_int8_t *)&ts.tv_sec,
sizeof(ts.tv_sec), NULL, (u_int8_t *)&seed);
} while (seed == 0);
if (__os_csprng(env, &seed, sizeof(seed)) != 0 || seed == 0)
do {
__os_gettime(env, &ts, 1);
__db_chksum(NULL, (u_int8_t *)&ts.tv_sec,
sizeof(ts.tv_sec), NULL, (u_int8_t *)&seed);
} while (seed == 0);
__db_sgenrand((unsigned long)seed, env->mt, &env->mti);
}

Expand Down
10 changes: 10 additions & 0 deletions src/dbinc/db_int.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
#endif
#endif

/*
* getrandom(2) is declared in <sys/random.h> on glibc and in <unistd.h> on
* some others; include the header when we have it so os_csprng.c can call it.
*/
#ifdef HAVE_GETRANDOM
#ifdef HAVE_SYS_RANDOM_H
#include <sys/random.h>
#endif
#endif

#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
Expand Down
1 change: 1 addition & 0 deletions src/dbinc_auto/os_ext.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 109 additions & 0 deletions src/os/os_csprng.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2026 The libdb contributors.
*
* $Id$
*/

#include "db_config.h"

#include "db_int.h"

/*
* __os_csprng --
* Fill a buffer with cryptographically strong random bytes from the
* operating system.
*
* This is the entropy source for security-sensitive values (currently
* encryption initialization vectors). It is deliberately separate from
* the Mersenne Twister in src/crypto/mersenne: that generator is fine for
* sequence quality but is not a CSPRNG and was historically seeded from
* hashed wall-clock seconds, which is guessable.
*
* Returns 0 on success, or a non-zero error if no OS entropy source is
* available; callers MUST handle failure rather than silently falling back
* to a weak source.
*
* PUBLIC: int __os_csprng __P((ENV *, void *, size_t));
*/
int
__os_csprng(env, buf, len)
ENV *env;
void *buf;
size_t len;
{
u_int8_t *p;
size_t need;
#if defined(HAVE_GETRANDOM)
ssize_t n;
#endif
#if !defined(HAVE_ARC4RANDOM_BUF)
DB_FH *fhp;
size_t nr;
int ret;
#endif

p = buf;
need = len;

#ifdef HAVE_GETRANDOM
/*
* Linux (glibc 2.25+) / others: getrandom(2). It can return a short
* read, and can be interrupted, so loop. GRND_NONBLOCK is NOT used:
* we would rather block briefly at first use than fail or fall back to
* a weak source.
*/
while (need > 0) {
n = getrandom(p, need, 0);
if (n < 0) {
if (__os_get_syserr() == EINTR)
continue;
break; /* Fall through to /dev/urandom. */
}
p += n;
need -= (size_t)n;
}
if (need == 0)
return (0);
/* Reset and try the device. */
p = buf;
need = len;
#endif

#ifdef HAVE_ARC4RANDOM_BUF
/*
* The BSDs and macOS: arc4random_buf() cannot fail and needs no fd.
*/
arc4random_buf(p, need);
return (0);
#else
/*
* Portable fallback: read /dev/urandom. Use the OS layer so the file
* handling matches the rest of the library (DB_FH handle, not a raw fd).
*/
if ((ret = __os_open(env, "/dev/urandom", 0,
DB_OSO_RDONLY, DB_MODE_600, &fhp)) != 0)
return (ret);

while (need > 0) {
nr = 0;
if ((ret = __os_read(env, fhp, p, need, &nr)) != 0) {
(void)__os_closehandle(env, fhp);
return (ret);
}
if (nr == 0) /* Unexpected EOF. */
break;
p += nr;
need -= nr;
}
(void)__os_closehandle(env, fhp);

if (need != 0) {
__db_errx(env, DB_STR("0213",
"Unable to obtain random bytes from the operating system"));
return (EIO);
}
return (0);
#endif
}
64 changes: 64 additions & 0 deletions src/os_windows/os_csprng.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2026 The libdb contributors.
*
* $Id$
*/

#include "db_config.h"

#include "db_int.h"

/*
* __os_csprng --
* Fill a buffer with cryptographically strong random bytes from the
* operating system (Windows).
*
* This is the Windows counterpart of src/os/os_csprng.c and the entropy
* source for security-sensitive values (currently encryption
* initialization vectors). RtlGenRandom (exposed as SystemFunction036)
* is used rather than BCryptGenRandom: it needs no provider handle, has
* been available since Windows XP, and avoids linking bcrypt.lib.
*
* Returns 0 on success, or a non-zero error if the OS declines; callers
* MUST handle failure rather than silently falling back to a weak source.
*
* PUBLIC: int __os_csprng __P((ENV *, void *, size_t));
*/
int
__os_csprng(env, buf, len)
ENV *env;
void *buf;
size_t len;
{
/*
* RtlGenRandom is declared as SystemFunction036 in ntsecapi.h, which
* pulls in a large amount of unrelated interface; declare it directly
* the way Microsoft documents for this use.
*/
BOOLEAN (APIENTRY *pRtlGenRandom)(PVOID, ULONG);
HMODULE advapi;
int ret;

if (len == 0)
return (0);

ret = 0;
if ((advapi = LoadLibraryA("advapi32.dll")) == NULL)
goto err;

pRtlGenRandom = (BOOLEAN (APIENTRY *)(PVOID, ULONG))
GetProcAddress(advapi, "SystemFunction036");
if (pRtlGenRandom == NULL ||
!pRtlGenRandom(buf, (ULONG)len))
ret = EIO;

(void)FreeLibrary(advapi);
if (ret == 0)
return (0);

err: __db_errx(env, DB_STR("0214",
"Unable to obtain random bytes from the operating system"));
return (ret == 0 ? EIO : ret);
}
Loading