diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2017-08-25 10:51:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-28 14:34:58 -0400 |
commit | e702c1204eb57788ef189c839c8c779368267d70 (patch) | |
tree | ef7cfae25bf1b386f03c5dfb8c44266083d0c53b | |
parent | 4e4b21da3acc68a7ea55f850cacc13706b7480e9 (diff) |
l2tp: hold tunnel used while creating sessions with netlink
Use l2tp_tunnel_get() to retrieve tunnel, so that it can't go away on
us. Otherwise l2tp_tunnel_destruct() might release the last reference
count concurrently, thus freeing the tunnel while we're using it.
Fixes: 309795f4bec2 ("l2tp: Add netlink control API for L2TP")
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/l2tp/l2tp_netlink.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index ae5170e26281..57427d430f10 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -518,8 +518,9 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
518 | ret = -EINVAL; | 518 | ret = -EINVAL; |
519 | goto out; | 519 | goto out; |
520 | } | 520 | } |
521 | |||
521 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | 522 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); |
522 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 523 | tunnel = l2tp_tunnel_get(net, tunnel_id); |
523 | if (!tunnel) { | 524 | if (!tunnel) { |
524 | ret = -ENODEV; | 525 | ret = -ENODEV; |
525 | goto out; | 526 | goto out; |
@@ -527,24 +528,24 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
527 | 528 | ||
528 | if (!info->attrs[L2TP_ATTR_SESSION_ID]) { | 529 | if (!info->attrs[L2TP_ATTR_SESSION_ID]) { |
529 | ret = -EINVAL; | 530 | ret = -EINVAL; |
530 | goto out; | 531 | goto out_tunnel; |
531 | } | 532 | } |
532 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); | 533 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); |
533 | 534 | ||
534 | if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) { | 535 | if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) { |
535 | ret = -EINVAL; | 536 | ret = -EINVAL; |
536 | goto out; | 537 | goto out_tunnel; |
537 | } | 538 | } |
538 | peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]); | 539 | peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]); |
539 | 540 | ||
540 | if (!info->attrs[L2TP_ATTR_PW_TYPE]) { | 541 | if (!info->attrs[L2TP_ATTR_PW_TYPE]) { |
541 | ret = -EINVAL; | 542 | ret = -EINVAL; |
542 | goto out; | 543 | goto out_tunnel; |
543 | } | 544 | } |
544 | cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]); | 545 | cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]); |
545 | if (cfg.pw_type >= __L2TP_PWTYPE_MAX) { | 546 | if (cfg.pw_type >= __L2TP_PWTYPE_MAX) { |
546 | ret = -EINVAL; | 547 | ret = -EINVAL; |
547 | goto out; | 548 | goto out_tunnel; |
548 | } | 549 | } |
549 | 550 | ||
550 | if (tunnel->version > 2) { | 551 | if (tunnel->version > 2) { |
@@ -566,7 +567,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
566 | u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]); | 567 | u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]); |
567 | if (len > 8) { | 568 | if (len > 8) { |
568 | ret = -EINVAL; | 569 | ret = -EINVAL; |
569 | goto out; | 570 | goto out_tunnel; |
570 | } | 571 | } |
571 | cfg.cookie_len = len; | 572 | cfg.cookie_len = len; |
572 | memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len); | 573 | memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len); |
@@ -575,7 +576,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
575 | u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]); | 576 | u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]); |
576 | if (len > 8) { | 577 | if (len > 8) { |
577 | ret = -EINVAL; | 578 | ret = -EINVAL; |
578 | goto out; | 579 | goto out_tunnel; |
579 | } | 580 | } |
580 | cfg.peer_cookie_len = len; | 581 | cfg.peer_cookie_len = len; |
581 | memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len); | 582 | memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len); |
@@ -618,7 +619,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
618 | if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) || | 619 | if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) || |
619 | (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) { | 620 | (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) { |
620 | ret = -EPROTONOSUPPORT; | 621 | ret = -EPROTONOSUPPORT; |
621 | goto out; | 622 | goto out_tunnel; |
622 | } | 623 | } |
623 | 624 | ||
624 | /* Check that pseudowire-specific params are present */ | 625 | /* Check that pseudowire-specific params are present */ |
@@ -628,7 +629,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
628 | case L2TP_PWTYPE_ETH_VLAN: | 629 | case L2TP_PWTYPE_ETH_VLAN: |
629 | if (!info->attrs[L2TP_ATTR_VLAN_ID]) { | 630 | if (!info->attrs[L2TP_ATTR_VLAN_ID]) { |
630 | ret = -EINVAL; | 631 | ret = -EINVAL; |
631 | goto out; | 632 | goto out_tunnel; |
632 | } | 633 | } |
633 | break; | 634 | break; |
634 | case L2TP_PWTYPE_ETH: | 635 | case L2TP_PWTYPE_ETH: |
@@ -656,6 +657,8 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
656 | } | 657 | } |
657 | } | 658 | } |
658 | 659 | ||
660 | out_tunnel: | ||
661 | l2tp_tunnel_dec_refcount(tunnel); | ||
659 | out: | 662 | out: |
660 | return ret; | 663 | return ret; |
661 | } | 664 | } |