Florian Westphal says:

====================
netfilter: updates for net

The following patchset contains Netfilter fixes for *net*, all
for ancient problems.  Patch 7 raised drive-by sashiko findings,
but those are not related to the change itself.

1) Rebuild the nf_nat_sip data pointer to prevent stale access after SKB
reallocation. Restrict UDP mangling to UDP streams to avoid TCP packet
corruption.

2) Prevent undefined behavior in xt_u32 caused by invalid shift counts.
From Wyatt Feng.

3) Use u64 variables to prevent incorrect comparisons on links exceeding
34 Gbps in xt_rateest.  From Feng Wu.

4) Cap the number of expectations per master during nfnetlink_cthelper
updates. From Pablo Neira Ayuso.

5) Mark malformed IPv6 extension headers for hotdrop in ip6tables.
From Zhixing Chen.

6) Skip the end element of an open interval during the get command when its
closest match is the interval's start element. Also from Pablo Neira Ayuso.

7) Fix PMTU calculation for GUE/GRE tunnels in IPVS during ICMP fragmentation
error handling. Include additional tunnel header length when computing the
new MTU. From Yizhou Zhao.

8) Reset full ip_vs_seq structures in ip_vs_conn_new. Also from Yizhou Zhao.

9) Reject invalid shift parameters in xt_connmark. Also from Wyatt Feng.

netfilter pull request nf-26-07-03

* tag 'nf-26-07-03' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: xt_connmark: reject invalid shift parameters
  ipvs: reset full ip_vs_seq structs in ip_vs_conn_new
  ipvs: fix PMTU for GUE/GRE tunnel ICMP errors
  netfilter: nft_set_rbtree: get command skips end element with open interval
  netfilter: ip6tables: mark malformed IPv6 extension headers for hotdrop
  netfilter: nfnetlink_cthelper: cap to maximum number of expectation per master on updates
  netfilter: xt_rateest: fix u64 truncation in xt_rateest_mt()
  netfilter: xt_u32: reject invalid shift counts
  netfilter: nf_nat_sip: reload possible stale data pointer
====================

Link: https://patch.msgid.link/20260703125709.16493-1-fw@strlen.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni
2026-07-06 12:39:42 +02:00
12 changed files with 59 additions and 12 deletions

View File

@@ -56,6 +56,11 @@ static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par)
}
hdrlen = ipv6_authlen(ah);
if (skb->len - ptr < hdrlen) {
/* Packet smaller than its length field */
par->hotdrop = true;
return false;
}
pr_debug("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
pr_debug("RES %04X ", ah->reserved);

View File

@@ -75,6 +75,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
hdrlen = ipv6_optlen(oh);
if (skb->len - ptr < hdrlen) {
/* Packet smaller than it's length field */
par->hotdrop = true;
return false;
}

View File

@@ -56,7 +56,8 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
hdrlen = ipv6_optlen(rh);
if (skb->len - ptr < hdrlen) {
/* Pcket smaller than its length field */
/* Packet smaller than its length field */
par->hotdrop = true;
return false;
}

View File

@@ -1420,8 +1420,8 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
cp->app = NULL;
cp->app_data = NULL;
/* reset struct ip_vs_seq */
cp->in_seq.delta = 0;
cp->out_seq.delta = 0;
memset(&cp->in_seq, 0, sizeof(cp->in_seq));
memset(&cp->out_seq, 0, sizeof(cp->out_seq));
if (unlikely(flags & IP_VS_CONN_F_NO_CPORT)) {
int af_id = ip_vs_af_index(cp->af);

View File

@@ -1767,6 +1767,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
bool tunnel, new_cp = false;
union nf_inet_addr *raddr;
char *outer_proto = "IPIP";
int ulen = 0;
*related = 1;
@@ -1831,7 +1832,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
/* Error for our tunnel must arrive at LOCAL_IN */
(skb_rtable(skb)->rt_flags & RTCF_LOCAL)) {
__u8 iproto;
int ulen;
/* Non-first fragment has no UDP/GRE header */
if (unlikely(cih->frag_off & htons(IP_OFFSET)))
@@ -1936,8 +1936,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
if (dest_dst)
mtu = dst_mtu(dest_dst->dst_cache);
}
if (mtu > 68 + sizeof(struct iphdr))
mtu -= sizeof(struct iphdr);
if (mtu > 68 + sizeof(struct iphdr) + ulen)
mtu -= sizeof(struct iphdr) + ulen;
info = htonl(mtu);
}
/* Strip outer IP, ICMP and IPIP/UDP/GRE, go to IP header of

View File

@@ -289,13 +289,24 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
/* Mangle destination port for Cisco phones, then fix up checksums */
if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
int doff = *dptr - (const char *)skb->data;
struct udphdr *uh;
if (doff <= 0) {
DEBUG_NET_WARN_ON_ONCE(1);
return NF_DROP;
}
/* ct_sip_info->forced_dport only expected with UDP */
if (nf_ct_protonum(ct) != IPPROTO_UDP)
return NF_DROP;
if (skb_ensure_writable(skb, skb->len)) {
nf_ct_helper_log(skb, ct, "cannot mangle packet");
return NF_DROP;
}
*dptr = skb->data + doff;
uh = (void *)skb->data + protoff;
uh->dest = ct_sip_info->forced_dport;

View File

@@ -6563,6 +6563,9 @@ static int nft_get_set_elem(struct nft_ctx *ctx, const struct nft_set *set,
if (err < 0)
return err;
if (!elem.priv)
return 0;
err = -ENOMEM;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
if (skb == NULL)

View File

@@ -316,6 +316,8 @@ nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy,
new_policy->max_expected =
ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
if (!new_policy->max_expected)
new_policy->max_expected = NF_CT_EXPECT_MAX_CNT;
if (new_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
return -EINVAL;

View File

@@ -184,10 +184,14 @@ nft_rbtree_get(const struct net *net, const struct nft_set *set,
if (!interval || nft_set_elem_expired(interval->from))
return ERR_PTR(-ENOENT);
if (flags & NFT_SET_ELEM_INTERVAL_END)
if (flags & NFT_SET_ELEM_INTERVAL_END) {
if (!interval->to)
return NULL;
rbe = container_of(interval->to, struct nft_rbtree_elem, ext);
else
} else {
rbe = container_of(interval->from, struct nft_rbtree_elem, ext);
}
return &rbe->priv;
}

View File

@@ -112,6 +112,16 @@ static int connmark_tg_check(const struct xt_tgchk_param *par)
return ret;
}
static int connmark_tg_check_v2(const struct xt_tgchk_param *par)
{
const struct xt_connmark_tginfo2 *info = par->targinfo;
if (info->shift_dir > D_SHIFT_RIGHT || info->shift_bits >= 32)
return -EINVAL;
return connmark_tg_check(par);
}
static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
{
nf_ct_netns_put(par->net, par->family);
@@ -162,7 +172,7 @@ static struct xt_target connmark_tg_reg[] __read_mostly = {
.name = "CONNMARK",
.revision = 2,
.family = NFPROTO_IPV4,
.checkentry = connmark_tg_check,
.checkentry = connmark_tg_check_v2,
.target = connmark_tg_v2,
.targetsize = sizeof(struct xt_connmark_tginfo2),
.destroy = connmark_tg_destroy,
@@ -183,7 +193,7 @@ static struct xt_target connmark_tg_reg[] __read_mostly = {
.name = "CONNMARK",
.revision = 2,
.family = NFPROTO_IPV6,
.checkentry = connmark_tg_check,
.checkentry = connmark_tg_check_v2,
.target = connmark_tg_v2,
.targetsize = sizeof(struct xt_connmark_tginfo2),
.destroy = connmark_tg_destroy,

View File

@@ -16,7 +16,7 @@ xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_rateest_match_info *info = par->matchinfo;
struct gnet_stats_rate_est64 sample = {0};
u_int32_t bps1, bps2, pps1, pps2;
u64 bps1, bps2, pps1, pps2;
bool ret = true;
gen_estimator_read(&info->est1->rate_est, &sample);

View File

@@ -100,7 +100,7 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par)
{
const struct xt_u32 *data = par->matchinfo;
const struct xt_u32_test *ct;
unsigned int i;
unsigned int i, j;
if (data->ntests > ARRAY_SIZE(data->tests))
return -EINVAL;
@@ -111,6 +111,16 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par)
if (ct->nnums > ARRAY_SIZE(ct->location) ||
ct->nvalues > ARRAY_SIZE(ct->value))
return -EINVAL;
for (j = 1; j < ct->nnums; ++j) {
switch (ct->location[j].nextop) {
case XT_U32_LEFTSH:
case XT_U32_RIGHTSH:
if (ct->location[j].number >= 32)
return -EINVAL;
break;
}
}
}
return 0;