Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Aug 2026 08:15:39 +0000
From:      Andrey V. Elsukov <ae@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Cc:        Boris Lytochkin <lytboris@gmail.com>
Subject:   git: c64d42caebb7 - stable/14 - ipfw: rework 32-bit KBI detection
Message-ID:  <6a7ada2b.25e1f.260afbfb@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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,


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a7ada2b.25e1f.260afbfb>