The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=64bc9ac8cd9a42259aeb1715d4e14902aa83fcac
commit 64bc9ac8cd9a42259aeb1715d4e14902aa83fcac Author: Seyed Pouria Mousavizadeh Tehrani <p.mousaviza...@protonmail.com> AuthorDate: 2025-08-21 17:40:29 +0000 Commit: Dag-Erling Smørgrav <d...@freebsd.org> CommitDate: 2025-08-25 10:37:25 +0000 ipfw: Fix segfault in NPTv6 rule parser If the user specified a prefix length with either the internal or external prefix, we'd jump to check_prefix where we'd dereference p which was most likely uninitialized. Instead, store the various prefix lengths separately and check them all after the loop. MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D50597 --- sbin/ipfw/nptv6.c | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/sbin/ipfw/nptv6.c b/sbin/ipfw/nptv6.c index 83bf4c768fd9..eee6109a3d9e 100644 --- a/sbin/ipfw/nptv6.c +++ b/sbin/ipfw/nptv6.c @@ -153,10 +153,10 @@ static struct _s_x nptv6newcmds[] = { { NULL, 0 } }; - static void nptv6_parse_prefix(const char *arg, struct in6_addr *prefix, int *len) { + long plen; char *p, *l; p = strdup(arg); @@ -167,13 +167,15 @@ nptv6_parse_prefix(const char *arg, struct in6_addr *prefix, int *len) if (inet_pton(AF_INET6, p, prefix) != 1) errx(EX_USAGE, "Bad prefix: %s", p); if (l != NULL) { - *len = (int)strtol(l, &l, 10); - if (*l != '\0' || *len <= 0 || *len > 64) + plen = strtol(l, &l, 10); + if (*l != '\0' || plen < 8 || plen > 64) errx(EX_USAGE, "Bad prefix length: %s", arg); + *len = plen; } else *len = 0; free(p); } + /* * Creates new nptv6 instance * ipfw nptv6 <NAME> create int_prefix <prefix> ext_prefix <prefix> @@ -189,10 +191,10 @@ nptv6_create(const char *name, uint8_t set, int ac, char *av[]) struct in6_addr mask; ipfw_nptv6_cfg *cfg; ipfw_obj_lheader *olh; - int tcmd, flags, plen; + int tcmd, flags, iplen, eplen, pplen; char *p; - plen = 0; + iplen = eplen = pplen = 0; memset(buf, 0, sizeof(buf)); olh = (ipfw_obj_lheader *)buf; cfg = (ipfw_nptv6_cfg *)(olh + 1); @@ -205,10 +207,8 @@ nptv6_create(const char *name, uint8_t set, int ac, char *av[]) switch (tcmd) { case TOK_INTPREFIX: NEED1("IPv6 prefix required"); - nptv6_parse_prefix(*av, &cfg->internal, &plen); + nptv6_parse_prefix(*av, &cfg->internal, &iplen); flags |= NPTV6_HAS_INTPREFIX; - if (plen > 0) - goto check_prefix; ac--; av++; break; case TOK_EXTPREFIX: @@ -216,10 +216,8 @@ nptv6_create(const char *name, uint8_t set, int ac, char *av[]) errx(EX_USAGE, "Only one ext_prefix or ext_if allowed"); NEED1("IPv6 prefix required"); - nptv6_parse_prefix(*av, &cfg->external, &plen); + nptv6_parse_prefix(*av, &cfg->external, &eplen); flags |= NPTV6_HAS_EXTPREFIX; - if (plen > 0) - goto check_prefix; ac--; av++; break; case TOK_EXTIF: @@ -236,24 +234,29 @@ nptv6_create(const char *name, uint8_t set, int ac, char *av[]) break; case TOK_PREFIXLEN: NEED1("IPv6 prefix length required"); - plen = strtol(*av, &p, 10); -check_prefix: - if (*p != '\0' || plen < 8 || plen > 64) + pplen = strtol(*av, &p, 10); + if (*p != '\0' || pplen < 8 || pplen > 64) errx(EX_USAGE, "wrong prefix length: %s", *av); - /* RFC 6296 Sec. 3.1 */ - if (cfg->plen > 0 && cfg->plen != plen) { - warnx("Prefix length mismatch (%d vs %d). " - "It was extended up to %d", - cfg->plen, plen, MAX(plen, cfg->plen)); - plen = MAX(plen, cfg->plen); - } - cfg->plen = plen; - flags |= NPTV6_HAS_PREFIXLEN; ac--; av++; break; } } + /* RFC 6296 Sec. 3.1 */ + if (pplen != 0) { + if ((eplen != 0 && eplen != pplen) || + (iplen != 0 && iplen != pplen)) + errx(EX_USAGE, "prefix length mismatch"); + cfg->plen = pplen; + flags |= NPTV6_HAS_PREFIXLEN; + } else if (eplen != 0 || iplen != 0) { + if (eplen != 0 && iplen != 0 && eplen != iplen) + errx(EX_USAGE, "prefix length mismatch"); + warnx("use prefixlen instead"); + cfg->plen = eplen ? eplen : iplen; + flags |= NPTV6_HAS_PREFIXLEN; + } + /* Check validness */ if ((flags & NPTV6_HAS_INTPREFIX) != NPTV6_HAS_INTPREFIX) errx(EX_USAGE, "int_prefix required");