ipv6: Fix 'inet6_rtm_getroute' to release 'rt->dst' in case of 'alloc_skb' failure
[cascardo/linux.git] / net / ipv6 / route.c
index 3992e26..8c5df6f 100644 (file)
@@ -2413,7 +2413,8 @@ static int rt6_fill_node(struct net *net,
        else
                table = RT6_TABLE_UNSPEC;
        rtm->rtm_table = table;
-       NLA_PUT_U32(skb, RTA_TABLE, table);
+       if (nla_put_u32(skb, RTA_TABLE, table))
+               goto nla_put_failure;
        if (rt->rt6i_flags & RTF_REJECT)
                rtm->rtm_type = RTN_UNREACHABLE;
        else if (rt->rt6i_flags & RTF_LOCAL)
@@ -2436,16 +2437,20 @@ static int rt6_fill_node(struct net *net,
                rtm->rtm_flags |= RTM_F_CLONED;
 
        if (dst) {
-               NLA_PUT(skb, RTA_DST, 16, dst);
+               if (nla_put(skb, RTA_DST, 16, dst))
+                       goto nla_put_failure;
                rtm->rtm_dst_len = 128;
        } else if (rtm->rtm_dst_len)
-               NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
+               if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
+                       goto nla_put_failure;
 #ifdef CONFIG_IPV6_SUBTREES
        if (src) {
-               NLA_PUT(skb, RTA_SRC, 16, src);
+               if (nla_put(skb, RTA_SRC, 16, src))
+                       goto nla_put_failure;
                rtm->rtm_src_len = 128;
-       } else if (rtm->rtm_src_len)
-               NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+       } else if (rtm->rtm_src_len &&
+                  nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
+               goto nla_put_failure;
 #endif
        if (iif) {
 #ifdef CONFIG_IPV6_MROUTE
@@ -2463,17 +2468,20 @@ static int rt6_fill_node(struct net *net,
                        }
                } else
 #endif
-                       NLA_PUT_U32(skb, RTA_IIF, iif);
+                       if (nla_put_u32(skb, RTA_IIF, iif))
+                               goto nla_put_failure;
        } else if (dst) {
                struct in6_addr saddr_buf;
-               if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
-                       NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+               if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
+                   nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
+                       goto nla_put_failure;
        }
 
        if (rt->rt6i_prefsrc.plen) {
                struct in6_addr saddr_buf;
                saddr_buf = rt->rt6i_prefsrc.addr;
-               NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+               if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
+                       goto nla_put_failure;
        }
 
        if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
@@ -2489,11 +2497,11 @@ static int rt6_fill_node(struct net *net,
        }
        rcu_read_unlock();
 
-       if (rt->dst.dev)
-               NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
-
-       NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
-
+       if (rt->dst.dev &&
+           nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
+               goto nla_put_failure;
+       if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
+               goto nla_put_failure;
        if (!(rt->rt6i_flags & RTF_EXPIRES))
                expires = 0;
        else if (rt->dst.expires - jiffies < INT_MAX)
@@ -2598,6 +2606,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!skb) {
+               dst_release(&rt->dst);
                err = -ENOBUFS;
                goto errout;
        }