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>
