git: c64d42caebb7 - stable/14 - ipfw: rework 32-bit KBI detection
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 11 Aug 2026 08:15:39 UTC
The branch stable/14 has been updated by ae:
URL: https://cgit.FreeBSD.org/src/commit/?id=c64d42caebb77f927777408f5a284a7313df1fc4
commit c64d42caebb77f927777408f5a284a7313df1fc4
Author: Boris Lytochkin <lytboris@gmail.com>
AuthorDate: 2026-08-11 08:03:16 +0000
Commit: Andrey V. Elsukov <ae@FreeBSD.org>
CommitDate: 2026-08-11 08:03:16 +0000
ipfw: rework 32-bit KBI detection
When we run 14.X jail on 15.X host system previous implementation could
not correctly detect 32-bit KBI due to jails can overwrite osreldate.
Add special handling for this case and use detection using
IP_FW_DUMP_SOPTCODES and IP_FW_XGET sockopts version.
Reported by: Vova Grebenschikov
Fixes: 704ec5e68c44
MFC after: 3 days
Differential Revision: https://reviews.freebsd.org/D56616
---
sbin/ipfw/ipfw2.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
sbin/ipfw/ipfw2.h | 1 +
sbin/ipfw/main.c | 14 ++++----
3 files changed, 110 insertions(+), 7 deletions(-)
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 56e5b0640135..a8a70dccf125 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -33,6 +33,7 @@
#include <jail.h>
#include <netdb.h>
#include <pwd.h>
+#include <osreldate.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
@@ -5829,6 +5830,107 @@ ipfw_internal_handler(int ac, char *av[])
}
}
+/*
+ * Detect 32 bit ipfw KBI by presence of XGET v=1.
+ *
+ * 32-bit KBI was introduced in 1500034. Report 32-bit KBI for osreldate equal
+ * or greater than 1500034. For lower values, jailed status must be checked to
+ * make sure getosreldate() returned a real value as jail init can be
+ * instructed to override this value (see jail(8)). In case we're in a jail,
+ * use ipfw socket to detect 32-bit KBI using ophandler probes.
+ *
+ * Return:
+ * 2 - 32-bit opcode KBI detected despite of getosreldate() retval
+ * 1 - 32-bit opcode KBI detected
+ * 0 - 16-bit opcode KBI detected
+ * -1 - an error occurred
+ */
+
+int
+ipfw_detect_u32_kbi(void)
+{
+ ipfw_obj_lheader *hdr = NULL;
+ ipfw_sopt_info *info;
+ socklen_t len;
+ size_t need;
+ uint32_t i;
+ int s, opver, ret = -1;
+
+ if (getosreldate() >= 1500034)
+ return (1);
+
+ /* Make more checks for lower osreldate values */
+ s = 0;
+ need = sizeof(s);
+ sysctlbyname("security.jail.jailed", &s, &need, NULL, 0);
+
+ /* We're not in a jail, value from getosreldate() is real */
+ if (s == 0)
+ return (0);
+
+ /*
+ * We're in a jail, osreldate may be altered. Use ipfw socket to
+ * decide.
+ */
+ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (s < 0)
+ return (-1);
+
+ /*
+ * ipfw code @ RELENG_15 can register 61 sockopt handlers.
+ * Pre-allocate enough to evade realloc()
+ */
+ need = sizeof(ipfw_obj_lheader) + (64 * sizeof(ipfw_sopt_info));
+
+ opver = 0;
+ for (i = 4; i >= 0; i--) {
+ hdr = realloc(hdr, need);
+ memset(hdr, 0, need);
+ if (hdr == NULL)
+ break;
+
+ hdr->opheader.opcode = IP_FW_DUMP_SOPTCODES;
+ hdr->opheader.version = opver;
+ hdr->size = need;
+
+ /* Check DUMP_SOPTCODES v=1 existance */
+ len = need;
+ if (getsockopt(s, IPPROTO_IP, IP_FW3, hdr, &len) != 0) {
+ if (errno == ENOMEM) {
+ need = hdr->size;
+ continue;
+ }
+ /* Does not exist. 32-bit KBI? */
+ if (errno == EINVAL && opver == 0) {
+ opver = 1;
+ continue;
+ }
+ /* Report an error */
+ ret = -1;
+ break;
+ }
+ /* Fetched soptcodes successfully */
+ info = (ipfw_sopt_info *)(hdr + 1);
+ for (i = 0; i < hdr->count; i++) {
+ if (info[i].opcode != IP_FW_XGET)
+ continue;
+ if (info[i].version == 0) {
+ ret = 0;
+ break;
+ }
+ if (info[i].version == 1) {
+ ret = 2;
+ break;
+ }
+ }
+ break;
+ }
+
+ free(hdr);
+ close(s);
+ return (ret);
+}
+
static int
ipfw_get_tracked_ifaces(ipfw_obj_lheader **polh)
{
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 2137719296f9..58b73a627bd7 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -454,6 +454,7 @@ int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
void bp_flush(struct buf_pr *b);
void fill_table(struct _ipfw_insn *cmd, char *av, uint8_t opcode,
struct tidx *tstate);
+int ipfw_detect_u32_kbi(void);
/* tables.c */
struct _ipfw_obj_ctlv;
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index 3d5cfc96af46..2ad521bdbea4 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -18,7 +18,6 @@
* Command line interface for IP firewall facility
*/
-#include <sys/stat.h>
#include <sys/wait.h>
#include <ctype.h>
#include <err.h>
@@ -31,8 +30,6 @@
#include <unistd.h>
#include <libgen.h>
-#include <osreldate.h>
-
#include "ipfw2.h"
static void
@@ -673,6 +670,7 @@ ipfw_readfile(int ac, char *av[])
int
main(int ac, char *av[])
{
+ int ret;
#if defined(_WIN32) && defined(TCC)
{
WSADATA wsaData;
@@ -697,17 +695,19 @@ main(int ac, char *av[])
* KBI-incompatibility detected, check for availability of ipfw/dnctl15
* binaries and run them instead
*/
- if (getosreldate() >= 1500000) {
+ ret = ipfw_detect_u32_kbi();
+ if (ret > 0) {
const char *releng15_progname;
- int ret;
if (g_co.prog == cmdline_prog_ipfw)
releng15_progname = "/sbin/ipfw15";
else
releng15_progname = "/sbin/dnctl15";
- printf("WARNING! KBI incompatibility for ipfw is detected,"
- " trying to run %s.\n", releng15_progname);
+ if (ret == 1)
+ printf("WARNING! KBI incompatibility for ipfw is"
+ " detected, trying to run %s.\n",
+ releng15_progname);
if ((ret = execv(releng15_progname, av)) < 0) {
printf("execv(%s) error: %s\n", releng15_progname,