From: Li RongQing <redacted>
Fix a use-after-free bug in ip4ip6_err() where rt->rt_flags is accessed
after the route entry object has been released via ip_rt_put(rt).
If ip_rt_put() decrements the reference count to zero and frees the
rtable structure, reading rt->rt_flags immediately afterward
results in a use-after-free pointer dereference.
Fix this by caching rt->rt_flags into a local variable before calling
ip_rt_put().
Fixes: 77552cfa39c4 ("ip6_tunnel: clean up ip4ip6 and ip6ip6's err_handlers")
Signed-off-by: Li RongQing <redacted>
---
net/ipv6/ip6_tunnel.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index bf8e40a..984cb0c 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -569,6 +569,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
{
__u32 rel_info = ntohl(info);
const struct iphdr *eiph;
+ unsigned int rt_flags;
struct sk_buff *skb2;
int err, rel_msg = 0;
u8 rel_type = type;@@ -627,10 +628,11 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
goto out;
skb2->dev = rt->dst.dev;
+ rt_flags = rt->rt_flags;
ip_rt_put(rt);
/* route "incoming" packet */
- if (rt->rt_flags & RTCF_LOCAL) {
+ if (rt_flags & RTCF_LOCAL) {
rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
eiph->daddr, eiph->saddr, 0, 0,
IPPROTO_IPIP,--
2.9.4