* [PATCH nf v2] netfilter: ip6tables: set hotdrop for malformed extension header matches
@ 2026-07-14 3:21 Zhixing Chen
2026-07-14 22:26 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: Zhixing Chen @ 2026-07-14 3:21 UTC (permalink / raw)
To: Florian Westphal, Pablo Neira Ayuso, Phil Sutter
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, netfilter-devel, coreteam, netdev, Zhixing Chen
The hbh, srh and ipv6header matches have paths that return false for
malformed IPv6 extension header packets without setting hotdrop.
For hbh, strict option parsing stops when the option type or length field
cannot be read, or when advancing to the next requested option would
exceed the available header data. Mark these packets for hotdrop instead
of treating them as a rule mismatch.
For srh, keep a missing SRH as a normal mismatch, but set hotdrop when
header lookup fails for other reasons, when the SRH fixed header is not
present, when the advertised SRH length exceeds the available skb data,
when segments_left exceeds first_segment, or when SID selector reads fail.
For ipv6header, set hotdrop when the advertised extension header length
exceeds the available skb data.
Returning false treats the packet as a rule mismatch. Set hotdrop for
these malformed packets so they cannot bypass rules intended to drop
packets with these IPv6 extension headers.
Signed-off-by: Zhixing Chen <running910@gmail.com>
---
Changes in v2:
- Use hotdrop labels for hbh and srh paths.
- Mark SRH packets with segments_left greater than first_segment for
hotdrop.
- Drop the redundant ipv6header length check before skb_header_pointer().
v1: https://lore.kernel.org/netdev/20260709063012.33160-1-running910@gmail.com/T/
---
net/ipv6/netfilter/ip6t_hbh.c | 27 ++++++++++---------
| 9 +++----
net/ipv6/netfilter/ip6t_srh.c | 40 ++++++++++++++++++++--------
3 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 6d1a5d2026a6..1b5dcc92b7da 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -62,21 +62,18 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
NEXTHDR_HOP : NEXTHDR_DEST, NULL, NULL);
if (err < 0) {
if (err != -ENOENT)
- par->hotdrop = true;
+ goto hotdrop;
return false;
}
oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
- if (oh == NULL) {
- par->hotdrop = true;
- return false;
- }
+ if (!oh)
+ goto hotdrop;
hdrlen = ipv6_optlen(oh);
if (skb->len - ptr < hdrlen) {
/* Packet smaller than it's length field */
- par->hotdrop = true;
- return false;
+ goto hotdrop;
}
pr_debug("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
@@ -104,8 +101,8 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
break;
tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
&_opttype);
- if (tp == NULL)
- break;
+ if (!tp)
+ goto hotdrop;
/* Type check */
if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) {
@@ -121,12 +118,12 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
/* length field exists ? */
if (hdrlen < 2)
- break;
+ goto hotdrop;
lp = skb_header_pointer(skb, ptr + 1,
sizeof(_optlen),
&_optlen);
- if (lp == NULL)
- break;
+ if (!lp)
+ goto hotdrop;
spec_len = optinfo->opts[temp] & 0x00FF;
if (spec_len != 0x00FF && spec_len != *lp) {
@@ -147,7 +144,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
if ((ptr > skb->len - optlen || hdrlen < optlen) &&
temp < optinfo->optsnr - 1) {
pr_debug("new pointer is too large!\n");
- break;
+ goto hotdrop;
}
ptr += optlen;
hdrlen -= optlen;
@@ -159,6 +156,10 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
}
return false;
+
+hotdrop:
+ par->hotdrop = true;
+ return false;
}
static int hbh_mt6_check(const struct xt_mtchk_param *par)
--git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index c52ff929c93b..e339cefc7fff 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -52,9 +52,6 @@ ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par)
temp |= MASK_NONE;
break;
}
- /* Is there enough space for the next ext header? */
- if (len < (int)sizeof(struct ipv6_opt_hdr))
- return false;
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
temp |= MASK_ESP;
@@ -99,8 +96,10 @@ ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par)
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
- if (ptr > skb->len)
- break;
+ if (ptr > skb->len) {
+ par->hotdrop = true;
+ return false;
+ }
}
if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP)
diff --git a/net/ipv6/netfilter/ip6t_srh.c b/net/ipv6/netfilter/ip6t_srh.c
index db0fd64d8986..321c7f40a24f 100644
--- a/net/ipv6/netfilter/ip6t_srh.c
+++ b/net/ipv6/netfilter/ip6t_srh.c
@@ -27,22 +27,27 @@ static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
struct ipv6_sr_hdr *srh;
struct ipv6_sr_hdr _srh;
int hdrlen, srhoff = 0;
+ int err;
- if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
+ err = ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL);
+ if (err < 0) {
+ if (err != -ENOENT)
+ goto hotdrop;
return false;
+ }
srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
if (!srh)
- return false;
+ goto hotdrop;
hdrlen = ipv6_optlen(srh);
if (skb->len - srhoff < hdrlen)
- return false;
+ goto hotdrop;
if (srh->type != IPV6_SRCRT_TYPE_4)
return false;
if (srh->segments_left > srh->first_segment)
- return false;
+ goto hotdrop;
/* Next Header matching */
if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
@@ -111,6 +116,10 @@ static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
!(srh->tag == srhinfo->tag)))
return false;
return true;
+
+hotdrop:
+ par->hotdrop = true;
+ return false;
}
static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
@@ -121,22 +130,27 @@ static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
struct in6_addr _psid, _nsid, _lsid;
struct ipv6_sr_hdr *srh;
struct ipv6_sr_hdr _srh;
+ int err;
- if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
+ err = ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL);
+ if (err < 0) {
+ if (err != -ENOENT)
+ goto hotdrop;
return false;
+ }
srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
if (!srh)
- return false;
+ goto hotdrop;
hdrlen = ipv6_optlen(srh);
if (skb->len - srhoff < hdrlen)
- return false;
+ goto hotdrop;
if (srh->type != IPV6_SRCRT_TYPE_4)
return false;
if (srh->segments_left > srh->first_segment)
- return false;
+ goto hotdrop;
/* Next Header matching */
if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
@@ -207,7 +221,7 @@ static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
((srh->segments_left + 1) * sizeof(struct in6_addr));
psid = skb_header_pointer(skb, psidoff, sizeof(_psid), &_psid);
if (!psid)
- return false;
+ goto hotdrop;
if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_PSID,
ipv6_masked_addr_cmp(psid, &srhinfo->psid_msk,
&srhinfo->psid_addr)))
@@ -222,7 +236,7 @@ static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
((srh->segments_left - 1) * sizeof(struct in6_addr));
nsid = skb_header_pointer(skb, nsidoff, sizeof(_nsid), &_nsid);
if (!nsid)
- return false;
+ goto hotdrop;
if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NSID,
ipv6_masked_addr_cmp(nsid, &srhinfo->nsid_msk,
&srhinfo->nsid_addr)))
@@ -234,13 +248,17 @@ static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
lsidoff = srhoff + sizeof(struct ipv6_sr_hdr);
lsid = skb_header_pointer(skb, lsidoff, sizeof(_lsid), &_lsid);
if (!lsid)
- return false;
+ goto hotdrop;
if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LSID,
ipv6_masked_addr_cmp(lsid, &srhinfo->lsid_msk,
&srhinfo->lsid_addr)))
return false;
}
return true;
+
+hotdrop:
+ par->hotdrop = true;
+ return false;
}
static int srh_mt6_check(const struct xt_mtchk_param *par)
--
2.34.1
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH nf v2] netfilter: ip6tables: set hotdrop for malformed extension header matches
2026-07-14 3:21 [PATCH nf v2] netfilter: ip6tables: set hotdrop for malformed extension header matches Zhixing Chen
@ 2026-07-14 22:26 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2026-07-14 22:26 UTC (permalink / raw)
To: Zhixing Chen, Florian Westphal, Pablo Neira Ayuso, Phil Sutter
Cc: oe-kbuild-all, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, netfilter-devel, coreteam, netdev,
Zhixing Chen
Hi Zhixing,
kernel test robot noticed the following build warnings:
[auto build test WARNING on netfilter-nf/main]
[also build test WARNING on nf-next/main linus/master v7.2-rc3 next-20260713]
[cannot apply to linux-review/Zhixing-Chen/netfilter-ip6tables-set-hotdrop-for-malformed-extension-header-matches/20260709-143240 horms-ipvs/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Zhixing-Chen/netfilter-ip6tables-set-hotdrop-for-malformed-extension-header-matches/20260714-114506
base: https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git main
patch link: https://lore.kernel.org/r/20260714032124.7042-1-running910%40gmail.com
patch subject: [PATCH nf v2] netfilter: ip6tables: set hotdrop for malformed extension header matches
config: openrisc-allmodconfig (https://download.01.org/0day-ci/archive/20260715/202607150533.nQvx3zgH-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260715/202607150533.nQvx3zgH-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202607150533.nQvx3zgH-lkp@intel.com/
All warnings (new ones prefixed by >>):
net/ipv6/netfilter/ip6t_ipv6header.c: In function 'ipv6header_mt6':
>> net/ipv6/netfilter/ip6t_ipv6header.c:31:13: warning: variable 'len' set but not used [-Wunused-but-set-variable=]
31 | int len;
| ^~~
vim +/len +31 net/ipv6/netfilter/ip6t_ipv6header.c
^1da177e4c3f41 Linus Torvalds 2005-04-16 25
1d93a9cbad608f Jan Engelhardt 2007-07-07 26 static bool
62fc8051083a33 Jan Engelhardt 2009-07-07 27 ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par)
^1da177e4c3f41 Linus Torvalds 2005-04-16 28 {
f7108a20dee44e Jan Engelhardt 2008-10-08 29 const struct ip6t_ipv6header_info *info = par->matchinfo;
^1da177e4c3f41 Linus Torvalds 2005-04-16 30 unsigned int temp;
^1da177e4c3f41 Linus Torvalds 2005-04-16 @31 int len;
^1da177e4c3f41 Linus Torvalds 2005-04-16 32 u8 nexthdr;
^1da177e4c3f41 Linus Torvalds 2005-04-16 33 unsigned int ptr;
^1da177e4c3f41 Linus Torvalds 2005-04-16 34
^1da177e4c3f41 Linus Torvalds 2005-04-16 35 /* Make sure this isn't an evil packet */
^1da177e4c3f41 Linus Torvalds 2005-04-16 36
^1da177e4c3f41 Linus Torvalds 2005-04-16 37 /* type of the 1st exthdr */
0660e03f6b18f1 Arnaldo Carvalho de Melo 2007-04-25 38 nexthdr = ipv6_hdr(skb)->nexthdr;
^1da177e4c3f41 Linus Torvalds 2005-04-16 39 /* pointer to the 1st exthdr */
^1da177e4c3f41 Linus Torvalds 2005-04-16 40 ptr = sizeof(struct ipv6hdr);
^1da177e4c3f41 Linus Torvalds 2005-04-16 41 /* available length */
^1da177e4c3f41 Linus Torvalds 2005-04-16 42 len = skb->len - ptr;
^1da177e4c3f41 Linus Torvalds 2005-04-16 43 temp = 0;
^1da177e4c3f41 Linus Torvalds 2005-04-16 44
44dde23698a7a8 Jeremy Sowden 2019-09-13 45 while (nf_ip6_ext_hdr(nexthdr)) {
3cf93c96af7adf Jan Engelhardt 2008-04-14 46 const struct ipv6_opt_hdr *hp;
3cf93c96af7adf Jan Engelhardt 2008-04-14 47 struct ipv6_opt_hdr _hdr;
^1da177e4c3f41 Linus Torvalds 2005-04-16 48 int hdrlen;
^1da177e4c3f41 Linus Torvalds 2005-04-16 49
^1da177e4c3f41 Linus Torvalds 2005-04-16 50 /* No more exthdr -> evaluate */
^1da177e4c3f41 Linus Torvalds 2005-04-16 51 if (nexthdr == NEXTHDR_NONE) {
^1da177e4c3f41 Linus Torvalds 2005-04-16 52 temp |= MASK_NONE;
^1da177e4c3f41 Linus Torvalds 2005-04-16 53 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 54 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 55 /* ESP -> evaluate */
^1da177e4c3f41 Linus Torvalds 2005-04-16 56 if (nexthdr == NEXTHDR_ESP) {
^1da177e4c3f41 Linus Torvalds 2005-04-16 57 temp |= MASK_ESP;
^1da177e4c3f41 Linus Torvalds 2005-04-16 58 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 59 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 60
^1da177e4c3f41 Linus Torvalds 2005-04-16 61 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
70c0eb1ca016f7 Florian Westphal 2018-09-04 62 if (!hp) {
70c0eb1ca016f7 Florian Westphal 2018-09-04 63 par->hotdrop = true;
70c0eb1ca016f7 Florian Westphal 2018-09-04 64 return false;
70c0eb1ca016f7 Florian Westphal 2018-09-04 65 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 66
^1da177e4c3f41 Linus Torvalds 2005-04-16 67 /* Calculate the header length */
7c4e36bc172ae1 Jan Engelhardt 2007-07-07 68 if (nexthdr == NEXTHDR_FRAGMENT)
^1da177e4c3f41 Linus Torvalds 2005-04-16 69 hdrlen = 8;
7c4e36bc172ae1 Jan Engelhardt 2007-07-07 70 else if (nexthdr == NEXTHDR_AUTH)
416e8126a2672f yangxingwu 2019-07-10 71 hdrlen = ipv6_authlen(hp);
^1da177e4c3f41 Linus Torvalds 2005-04-16 72 else
^1da177e4c3f41 Linus Torvalds 2005-04-16 73 hdrlen = ipv6_optlen(hp);
^1da177e4c3f41 Linus Torvalds 2005-04-16 74
^1da177e4c3f41 Linus Torvalds 2005-04-16 75 /* set the flag */
^1da177e4c3f41 Linus Torvalds 2005-04-16 76 switch (nexthdr) {
^1da177e4c3f41 Linus Torvalds 2005-04-16 77 case NEXTHDR_HOP:
^1da177e4c3f41 Linus Torvalds 2005-04-16 78 temp |= MASK_HOPOPTS;
^1da177e4c3f41 Linus Torvalds 2005-04-16 79 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 80 case NEXTHDR_ROUTING:
^1da177e4c3f41 Linus Torvalds 2005-04-16 81 temp |= MASK_ROUTING;
^1da177e4c3f41 Linus Torvalds 2005-04-16 82 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 83 case NEXTHDR_FRAGMENT:
^1da177e4c3f41 Linus Torvalds 2005-04-16 84 temp |= MASK_FRAGMENT;
^1da177e4c3f41 Linus Torvalds 2005-04-16 85 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 86 case NEXTHDR_AUTH:
^1da177e4c3f41 Linus Torvalds 2005-04-16 87 temp |= MASK_AH;
^1da177e4c3f41 Linus Torvalds 2005-04-16 88 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 89 case NEXTHDR_DEST:
^1da177e4c3f41 Linus Torvalds 2005-04-16 90 temp |= MASK_DSTOPTS;
^1da177e4c3f41 Linus Torvalds 2005-04-16 91 break;
^1da177e4c3f41 Linus Torvalds 2005-04-16 92 default:
1d93a9cbad608f Jan Engelhardt 2007-07-07 93 return false;
^1da177e4c3f41 Linus Torvalds 2005-04-16 94 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 95
^1da177e4c3f41 Linus Torvalds 2005-04-16 96 nexthdr = hp->nexthdr;
^1da177e4c3f41 Linus Torvalds 2005-04-16 97 len -= hdrlen;
^1da177e4c3f41 Linus Torvalds 2005-04-16 98 ptr += hdrlen;
aebe9616a67760 Zhixing Chen 2026-07-14 99 if (ptr > skb->len) {
aebe9616a67760 Zhixing Chen 2026-07-14 100 par->hotdrop = true;
aebe9616a67760 Zhixing Chen 2026-07-14 101 return false;
aebe9616a67760 Zhixing Chen 2026-07-14 102 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 103 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 104
7c4e36bc172ae1 Jan Engelhardt 2007-07-07 105 if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP)
^1da177e4c3f41 Linus Torvalds 2005-04-16 106 temp |= MASK_PROTO;
^1da177e4c3f41 Linus Torvalds 2005-04-16 107
^1da177e4c3f41 Linus Torvalds 2005-04-16 108 if (info->modeflag)
^1da177e4c3f41 Linus Torvalds 2005-04-16 109 return !((temp ^ info->matchflags ^ info->invflags)
^1da177e4c3f41 Linus Torvalds 2005-04-16 110 & info->matchflags);
^1da177e4c3f41 Linus Torvalds 2005-04-16 111 else {
^1da177e4c3f41 Linus Torvalds 2005-04-16 112 if (info->invflags)
^1da177e4c3f41 Linus Torvalds 2005-04-16 113 return temp != info->matchflags;
^1da177e4c3f41 Linus Torvalds 2005-04-16 114 else
^1da177e4c3f41 Linus Torvalds 2005-04-16 115 return temp == info->matchflags;
^1da177e4c3f41 Linus Torvalds 2005-04-16 116 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 117 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 118
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-14 22:27 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-14 3:21 [PATCH nf v2] netfilter: ip6tables: set hotdrop for malformed extension header matches Zhixing Chen
2026-07-14 22:26 ` kernel test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.