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 lib/libc/gen/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CONFSMODE_master.passwd= 600
CONFSPACKAGE= runtime

SRCS+= __getosreldate.c \
__osrel_freebsd.c \
__pthread_mutex_init_calloc_cb_stub.c \
__xuname.c \
_once_stub.c \
Expand Down
12 changes: 9 additions & 3 deletions lib/libc/gen/__getosreldate.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
*
* Use getosreldate(3) for public use as it respects the $OSVERSION environment
* variable.
*
* The kernel reports a MidnightBSD version, but callers compare the result
* against FreeBSD versions, so it is translated by __osrel_to_freebsd().
*/

int
Expand All @@ -53,16 +56,19 @@ __getosreldate(void)
if (osreldate != 0)
return (osreldate);

error = _elf_aux_info(AT_OSRELDATE, &osreldate, sizeof(osreldate));
if (error == 0 && osreldate != 0)
osrel = 0;
error = _elf_aux_info(AT_OSRELDATE, &osrel, sizeof(osrel));
if (error == 0 && osrel != 0) {
osreldate = __osrel_to_freebsd(osrel);
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved
return (osreldate);
}

oid[0] = CTL_KERN;
oid[1] = KERN_OSRELDATE;
osrel = 0;
len = sizeof(osrel);
error = sysctl(oid, 2, &osrel, &len, NULL, 0);
if (error == 0 && osrel > 0 && len == sizeof(osrel))
osreldate = osrel;
osreldate = __osrel_to_freebsd(osrel);
return (osreldate);
}
87 changes: 87 additions & 0 deletions lib/libc/gen/__osrel_freebsd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2026 The MidnightBSD Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <sys/param.h>

#include "libc_private.h"

/*
* The kernel reports __MidnightBSD_version as its osreldate, but libc and
* rtld compare the value returned by __getosreldate() against FreeBSD
* version thresholds (INO64_FIRST, P_OSREL_*, ...). Translate a
* MidnightBSD version to the __FreeBSD_version of the tree that release
* was built from, so those checks see the features the kernel really has.
*
* Each entry is the first MidnightBSD version with that FreeBSD version.
* Where one MidnightBSD version spanned several FreeBSD versions, the
* lowest is used, so a feature is never assumed before it existed. Keep
* this table in sync with sys/sys/param.h when the FreeBSD base changes.
*/
static const struct {
int mnbsd;
int fbsd;
} osrel_map[] = {
{ 400001, 1305500 }, /* 4.0 */
{ 301006, 1204500 }, /* 3.1 */
{ 300003, 1203507 }, /* 3.0 */
{ 200000, 1103507 }, /* 2.0 */
{ 100001, 1004501 }, /* 1.0 */
};
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved

/*
* MidnightBSD versions are below the oldest FreeBSD version userland still
* checks for. Anything at or above this is already a FreeBSD version (for
* example, a jail created with a FreeBSD osreldate) and is returned
* unchanged.
*
* Values below this are always treated as MidnightBSD versions, even
* though FreeBSD 4-6 used the same range. That is safe: this code only
* runs in MidnightBSD userland, and a FreeBSD 4-6 jail runs its own libc
* and rtld, which never call it.
*/
#define OSREL_FREEBSD_MIN 700000
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved

int
__osrel_to_freebsd(int osrel)
{
size_t i;

if (osrel <= 0 || osrel >= OSREL_FREEBSD_MIN)
return (osrel);

/* A kernel at least as new as this libc has everything it knows. */
if (osrel >= __MidnightBSD_version)
return (__FreeBSD_version);

for (i = 0; i < nitems(osrel_map); i++) {
if (osrel >= osrel_map[i].mnbsd)
return (osrel_map[i].fbsd);
}

/* Older than any release with a FreeBSD 10 base. */
return (osrel);
}
6 changes: 6 additions & 0 deletions lib/libc/include/libc_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ extern void (*__cleanup)(void) __hidden;
* ignores value of $OSVERSION and caches result.
*/
int __getosreldate(void);

/*
* Translate a MidnightBSD osreldate to the matching __FreeBSD_version, for
* comparisons against FreeBSD version thresholds.
*/
int __osrel_to_freebsd(int);
#include <sys/_types.h>
#include <sys/_sigset.h>

Expand Down
6 changes: 6 additions & 0 deletions lib/libc/tests/gen/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ATF_TESTS_C+= getentropy_test
ATF_TESTS_C+= getmntinfo_test
ATF_TESTS_C+= glob2_test
ATF_TESTS_C+= makecontext_test
ATF_TESTS_C+= osrel_freebsd_test
ATF_TESTS_C+= popen_test
ATF_TESTS_C+= posix_spawn_test
ATF_TESTS_C+= realpath2_test
Expand Down Expand Up @@ -94,6 +95,11 @@ LIBADD.syslog_test+= pthread

CFLAGS+= -I${.CURDIR}

# __osrel_to_freebsd() is private to libc, so build its source into the test.
.PATH: ${SRCTOP}/lib/libc/gen
SRCS.osrel_freebsd_test= osrel_freebsd_test.c __osrel_freebsd.c
CFLAGS.__osrel_freebsd.c+= -I${SRCTOP}/lib/libc/include

SRCS.fmtcheck2_test= fmtcheck_test.c
SRCS.fnmatch2_test= fnmatch_test.c

Expand Down
111 changes: 111 additions & 0 deletions lib/libc/tests/gen/osrel_freebsd_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2026 The MidnightBSD Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

/*
* Tests for __osrel_to_freebsd(), which libc and rtld use to turn the
* kernel's MidnightBSD osreldate into a FreeBSD version for ABI checks.
* The function is private to libc, so its source is built into this test.
*/

#include <sys/param.h>
#include <sys/sysctl.h>

#include <atf-c.h>

int __osrel_to_freebsd(int);

Check failure on line 39 in lib/libc/tests/gen/osrel_freebsd_test.c

View workflow job for this annotation

GitHub Actions / Style Checker

style(9)

externs should be avoided in .c files

Check failure on line 39 in lib/libc/tests/gen/osrel_freebsd_test.c

View workflow job for this annotation

GitHub Actions / Style Checker

style(9)

externs should be avoided in .c files

Check failure on line 39 in lib/libc/tests/gen/osrel_freebsd_test.c

View workflow job for this annotation

GitHub Actions / Style Checker

style(9)

externs should be avoided in .c files

Check failure on line 39 in lib/libc/tests/gen/osrel_freebsd_test.c

View workflow job for this annotation

GitHub Actions / Style Checker

style(9)

externs should be avoided in .c files

Check failure on line 39 in lib/libc/tests/gen/osrel_freebsd_test.c

View workflow job for this annotation

GitHub Actions / Style Checker

style(9)

externs should be avoided in .c files

/* From lib/libc/sys/compat-ino64.h. */
#define INO64_FIRST 1200031

ATF_TC_WITHOUT_HEAD(passthrough);
ATF_TC_BODY(passthrough, tc)
{
/* Unset, invalid, and values that are already FreeBSD versions. */
ATF_CHECK_EQ(__osrel_to_freebsd(0), 0);
ATF_CHECK_EQ(__osrel_to_freebsd(-1), -1);
ATF_CHECK_EQ(__osrel_to_freebsd(700000), 700000);
ATF_CHECK_EQ(__osrel_to_freebsd(1305500), 1305500);
ATF_CHECK_EQ(__osrel_to_freebsd(1400000), 1400000);

/* Older than any release with a FreeBSD 10 base. */
ATF_CHECK_EQ(__osrel_to_freebsd(9005), 9005);
ATF_CHECK_EQ(__osrel_to_freebsd(100000), 100000);
}

ATF_TC_WITHOUT_HEAD(table_boundaries);
ATF_TC_BODY(table_boundaries, tc)
{
ATF_CHECK_EQ(__osrel_to_freebsd(100001), 1004501);
ATF_CHECK_EQ(__osrel_to_freebsd(199999), 1004501);
ATF_CHECK_EQ(__osrel_to_freebsd(200000), 1103507);
ATF_CHECK_EQ(__osrel_to_freebsd(300002), 1103507);
ATF_CHECK_EQ(__osrel_to_freebsd(300003), 1203507);
ATF_CHECK_EQ(__osrel_to_freebsd(301005), 1203507);
ATF_CHECK_EQ(__osrel_to_freebsd(301006), 1204500);
ATF_CHECK_EQ(__osrel_to_freebsd(400000), 1204500);
ATF_CHECK_EQ(__osrel_to_freebsd(400001), 1305500);
}

ATF_TC_WITHOUT_HEAD(current_release);
ATF_TC_BODY(current_release, tc)
{
/* A kernel at least as new as this libc maps to its FreeBSD base. */
ATF_CHECK_EQ(__osrel_to_freebsd(__MidnightBSD_version),
__FreeBSD_version);
ATF_CHECK_EQ(__osrel_to_freebsd(__MidnightBSD_version + 1),
__FreeBSD_version);
ATF_CHECK_EQ(__osrel_to_freebsd(699999), __FreeBSD_version);
}

ATF_TC_WITHOUT_HEAD(running_kernel);
ATF_TC_BODY(running_kernel, tc)
{
size_t len;
int osrel;

len = sizeof(osrel);
ATF_REQUIRE(sysctlbyname("kern.osreldate", &osrel, &len, NULL, 0) ==
0);

/*
* The running kernel has the ino64 syscalls, so libc must not fall
* back to the freebsd11 compat versions.
*/
ATF_CHECK_MSG(__osrel_to_freebsd(osrel) >= INO64_FIRST,
"kern.osreldate %d translates to %d, below INO64_FIRST", osrel,
__osrel_to_freebsd(osrel));
}

ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, passthrough);
ATF_TP_ADD_TC(tp, table_boundaries);
ATF_TP_ADD_TC(tp, current_release);
ATF_TP_ADD_TC(tp, running_kernel);

return (atf_no_error());
}
2 changes: 1 addition & 1 deletion libexec/rtld-elf/rtld-libc/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ CFLAGS.merge.c+=-Wno-error=null-pointer-arithmetic
.endif
.PATH: ${LIBC_SRCTOP}/gen
SRCS+= errlst.c getcwd.c getprogname.c raise.c sigsetops.c sysctlnametomib.c \
__xuname.c
__xuname.c __osrel_freebsd.c
# errlst.c needs the errlst.h header from libc:
CFLAGS.errlst.c+=-I${LIBC_SRCTOP}/include

Expand Down
1 change: 1 addition & 0 deletions libexec/rtld-elf/rtld-libc/rtld_libc.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ __ssize_t __sys_write(int, const void *, __size_t);
extern char* __progname;
const char *_getprogname(void);
int __getosreldate(void);
int __osrel_to_freebsd(int);


/*
Expand Down
4 changes: 2 additions & 2 deletions libexec/rtld-elf/rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -2424,7 +2424,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info)
#endif

if (aux_info[AT_OSRELDATE] != NULL)
osreldate = aux_info[AT_OSRELDATE]->a_un.a_val;
osreldate = __osrel_to_freebsd(aux_info[AT_OSRELDATE]->a_un.a_val);

digest_dynamic2(&obj_rtld, dyn_rpath, dyn_soname, dyn_runpath);

Expand Down Expand Up @@ -6355,7 +6355,7 @@ __getosreldate(void)
len = sizeof(osrel);
error = sysctl(oid, 2, &osrel, &len, NULL, 0);
if (error == 0 && osrel > 0 && len == sizeof(osrel))
osreldate = osrel;
osreldate = __osrel_to_freebsd(osrel);
return (osreldate);
}
const char *
Expand Down
Loading