When fetching the dst_entry from the skb, check if it valid, ie. this is not a template dst, for extensions that can be used from the netdev ingress and egress chains. Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_reject_ipv4.c | 6 ++++-- net/ipv6/netfilter/nf_reject_ipv6.c | 8 ++++++-- net/netfilter/nft_meta.c | 6 ++++-- net/netfilter/nft_rt.c | 6 ++++-- net/netfilter/nft_xfrm.c | 9 ++++++++- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index 4626dc46808f..59ec465a9df9 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -263,6 +264,7 @@ static int nf_reject_fill_skb_dst(struct sk_buff *skb_in) if (!dst) return -1; + skb_dst_drop(skb_in); skb_dst_set(skb_in, dst); return 0; } @@ -279,7 +281,7 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb, if (!oth) return; - if (!skb_dst(oldskb) && nf_reject_fill_skb_dst(oldskb) < 0) + if (!skb_valid_dst(oldskb) && nf_reject_fill_skb_dst(oldskb) < 0) return; if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) @@ -352,7 +354,7 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook) if (iph->frag_off & htons(IP_OFFSET)) return; - if (!skb_dst(skb_in) && nf_reject_fill_skb_dst(skb_in) < 0) + if (!skb_valid_dst(skb_in) && nf_reject_fill_skb_dst(skb_in) < 0) return; if (skb_csum_unnecessary(skb_in) || diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index ef5b7e85cffa..07cdaa10da0d 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -304,6 +305,7 @@ static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in) if (!dst) return -1; + skb_dst_drop(skb_in); skb_dst_set(skb_in, dst); return 0; } @@ -336,10 +338,12 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb, fl6.fl6_sport = otcph->dest; fl6.fl6_dport = otcph->source; - if (!skb_dst(oldskb)) { + if (!skb_valid_dst(oldskb)) { nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false); if (!dst) return; + + skb_dst_drop(oldskb); skb_dst_set(oldskb, dst); } @@ -440,7 +444,7 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) skb_in->dev = net->loopback_dev; - if (!skb_dst(skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0) + if (!skb_valid_dst(skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0) return; icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 0a43e0787a68..01cfbaa36525 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* for TCP_TIME_WAIT */ #include #include @@ -279,11 +280,12 @@ static bool nft_meta_get_eval_ifname(enum nft_meta_keys key, u32 *dest, static noinline bool nft_meta_get_eval_rtclassid(const struct sk_buff *skb, u32 *dest) { - const struct dst_entry *dst = skb_dst(skb); + const struct dst_entry *dst; - if (!dst) + if (!skb_valid_dst(skb)) return false; + dst = skb_dst(skb); *dest = dst->tclassid; return true; } diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c index aeb0094eafd8..841c863a08db 100644 --- a/net/netfilter/nft_rt.c +++ b/net/netfilter/nft_rt.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -59,10 +60,11 @@ void nft_rt_get_eval(const struct nft_expr *expr, u32 *dest = ®s->data[priv->dreg]; const struct dst_entry *dst; - dst = skb_dst(skb); - if (!dst) + if (!skb_valid_dst(skb)) goto err; + dst = skb_dst(skb); + switch (priv->key) { #ifdef CONFIG_IP_ROUTE_CLASSID case NFT_RT_CLASSID: diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c index 8cec43064319..c8bba697f993 100644 --- a/net/netfilter/nft_xfrm.c +++ b/net/netfilter/nft_xfrm.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -177,9 +178,15 @@ static void nft_xfrm_get_eval_out(const struct nft_xfrm *priv, struct nft_regs *regs, const struct nft_pktinfo *pkt) { - const struct dst_entry *dst = skb_dst(pkt->skb); + const struct dst_entry *dst; int i; + if (!skb_valid_dst(pkt->skb)) { + regs->verdict.code = NFT_BREAK; + return; + } + + dst = skb_dst(pkt->skb); for (i = 0; dst && dst->xfrm; dst = ((const struct xfrm_dst *)dst)->child, i++) { if (i < priv->spnum) -- 2.47.3