Skip to content

Commit

Permalink
netfilter: move br_nf_check_hbh_len to utils
Browse files Browse the repository at this point in the history
Rename br_nf_check_hbh_len() to nf_ip6_check_hbh_len() and move it
to netfilter utils, so that it can be used by other modules, like
ovs and tc.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
  • Loading branch information
Xin Long authored and Florian Westphal committed Mar 8, 2023
1 parent 0b24bd7 commit 28e144c
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 54 deletions.
2 changes: 2 additions & 0 deletions include/linux/netfilter_ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ static inline int nf_cookie_v6_check(const struct ipv6hdr *iph,
__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol);

int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen);

int ipv6_netfilter_init(void);
void ipv6_netfilter_fini(void);

Expand Down
55 changes: 1 addition & 54 deletions net/bridge/br_netfilter_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,59 +40,6 @@
#include <linux/sysctl.h>
#endif

/* We only check the length. A bridge shouldn't do any hop-by-hop stuff
* anyway
*/
static int br_nf_check_hbh_len(struct sk_buff *skb, u32 *plen)
{
int len, off = sizeof(struct ipv6hdr);
unsigned char *nh;

if (!pskb_may_pull(skb, off + 8))
return -1;
nh = (unsigned char *)(ipv6_hdr(skb) + 1);
len = (nh[1] + 1) << 3;

if (!pskb_may_pull(skb, off + len))
return -1;
nh = skb_network_header(skb);

off += 2;
len -= 2;
while (len > 0) {
int optlen;

if (nh[off] == IPV6_TLV_PAD1) {
off++;
len--;
continue;
}
if (len < 2)
return -1;
optlen = nh[off + 1] + 2;
if (optlen > len)
return -1;

if (nh[off] == IPV6_TLV_JUMBO) {
u32 pkt_len;

if (nh[off + 1] != 4 || (off & 3) != 2)
return -1;
pkt_len = ntohl(*(__be32 *)(nh + off + 2));
if (pkt_len <= IPV6_MAXPLEN ||
ipv6_hdr(skb)->payload_len)
return -1;
if (pkt_len > skb->len - sizeof(struct ipv6hdr))
return -1;
*plen = pkt_len;
}
off += optlen;
len -= optlen;
}

return len ? -1 : 0;
}

int br_validate_ipv6(struct net *net, struct sk_buff *skb)
{
const struct ipv6hdr *hdr;
Expand All @@ -112,7 +59,7 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb)
goto inhdr_error;

pkt_len = ntohs(hdr->payload_len);
if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb, &pkt_len))
if (hdr->nexthdr == NEXTHDR_HOP && nf_ip6_check_hbh_len(skb, &pkt_len))
goto drop;

if (pkt_len + ip6h_len > skb->len) {
Expand Down
52 changes: 52 additions & 0 deletions net/netfilter/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,55 @@ int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
}
return ret;
}

/* Only get and check the lengths, not do any hop-by-hop stuff. */
int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen)
{
int len, off = sizeof(struct ipv6hdr);
unsigned char *nh;

if (!pskb_may_pull(skb, off + 8))
return -ENOMEM;
nh = (unsigned char *)(ipv6_hdr(skb) + 1);
len = (nh[1] + 1) << 3;

if (!pskb_may_pull(skb, off + len))
return -ENOMEM;
nh = skb_network_header(skb);

off += 2;
len -= 2;
while (len > 0) {
int optlen;

if (nh[off] == IPV6_TLV_PAD1) {
off++;
len--;
continue;
}
if (len < 2)
return -EBADMSG;
optlen = nh[off + 1] + 2;
if (optlen > len)
return -EBADMSG;

if (nh[off] == IPV6_TLV_JUMBO) {
u32 pkt_len;

if (nh[off + 1] != 4 || (off & 3) != 2)
return -EBADMSG;
pkt_len = ntohl(*(__be32 *)(nh + off + 2));
if (pkt_len <= IPV6_MAXPLEN ||
ipv6_hdr(skb)->payload_len)
return -EBADMSG;
if (pkt_len > skb->len - sizeof(struct ipv6hdr))
return -EBADMSG;
*plen = pkt_len;
}
off += optlen;
len -= optlen;
}

return len ? -EBADMSG : 0;
}
EXPORT_SYMBOL_GPL(nf_ip6_check_hbh_len);

0 comments on commit 28e144c

Please sign in to comment.