diff options
author | Alexey Kodanev <alexey.kodanev@oracle.com> | 2018-02-05 07:10:35 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-05 21:21:13 -0500 |
commit | 957d761cf91cdbb175ad7d8f5472336a4d54dbf2 (patch) | |
tree | df4f3d6438373a5ed0a6b8e0db5f48dabdb975cd | |
parent | 23ddd2612d0e9b8c61d3c70960f1b1e8b64a1c4b (diff) |
sctp: fix dst refcnt leak in sctp_v6_get_dst()
When going through the bind address list in sctp_v6_get_dst() and
the previously found address is better ('matchlen > bmatchlen'),
the code continues to the next iteration without releasing currently
held destination.
Fix it by releasing 'bdst' before continue to the next iteration, and
instead of introducing one more '!IS_ERR(bdst)' check for dst_release(),
move the already existed one right after ip6_dst_lookup_flow(), i.e. we
shouldn't proceed further if we get an error for the route lookup.
Fixes: dbc2b5e9a09e ("sctp: fix src address selection if using secondary addresses for ipv6")
Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/sctp/ipv6.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 5d4c15bf66d2..e35d4f73d2df 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -326,8 +326,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
326 | final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); | 326 | final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); |
327 | bdst = ip6_dst_lookup_flow(sk, fl6, final_p); | 327 | bdst = ip6_dst_lookup_flow(sk, fl6, final_p); |
328 | 328 | ||
329 | if (!IS_ERR(bdst) && | 329 | if (IS_ERR(bdst)) |
330 | ipv6_chk_addr(dev_net(bdst->dev), | 330 | continue; |
331 | |||
332 | if (ipv6_chk_addr(dev_net(bdst->dev), | ||
331 | &laddr->a.v6.sin6_addr, bdst->dev, 1)) { | 333 | &laddr->a.v6.sin6_addr, bdst->dev, 1)) { |
332 | if (!IS_ERR_OR_NULL(dst)) | 334 | if (!IS_ERR_OR_NULL(dst)) |
333 | dst_release(dst); | 335 | dst_release(dst); |
@@ -336,8 +338,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
336 | } | 338 | } |
337 | 339 | ||
338 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | 340 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); |
339 | if (matchlen > bmatchlen) | 341 | if (matchlen > bmatchlen) { |
342 | dst_release(bdst); | ||
340 | continue; | 343 | continue; |
344 | } | ||
341 | 345 | ||
342 | if (!IS_ERR_OR_NULL(dst)) | 346 | if (!IS_ERR_OR_NULL(dst)) |
343 | dst_release(dst); | 347 | dst_release(dst); |