diff options
author | Chidambar 'ilLogict' Zinnoury <illogict@online.fr> | 2008-03-11 21:05:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-11 21:05:02 -0400 |
commit | 22626216c46f2ec86287e75ea86dd9ac3df54265 (patch) | |
tree | ee7fb381a17fb8105b7f2f8cd40cc4b587d064d0 /net/sctp/protocol.c | |
parent | b2211a361a4289c83971f89da53fe2eb9e72769d (diff) |
[SCTP]: Fix local_addr deletions during list traversals.
Since the lists are circular, we need to explicitely tag
the address to be deleted since we might end up freeing
the list head instead. This fixes some interesting SCTP
crashes.
Signed-off-by: Chidambar 'ilLogict' Zinnoury <illogict@online.fr>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/protocol.c')
-rw-r--r-- | net/sctp/protocol.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 688546dccd82..ad0a4069b95b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -628,6 +628,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, | |||
628 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; | 628 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; |
629 | struct sctp_sockaddr_entry *addr = NULL; | 629 | struct sctp_sockaddr_entry *addr = NULL; |
630 | struct sctp_sockaddr_entry *temp; | 630 | struct sctp_sockaddr_entry *temp; |
631 | int found = 0; | ||
631 | 632 | ||
632 | switch (ev) { | 633 | switch (ev) { |
633 | case NETDEV_UP: | 634 | case NETDEV_UP: |
@@ -647,13 +648,14 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, | |||
647 | list_for_each_entry_safe(addr, temp, | 648 | list_for_each_entry_safe(addr, temp, |
648 | &sctp_local_addr_list, list) { | 649 | &sctp_local_addr_list, list) { |
649 | if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) { | 650 | if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) { |
651 | found = 1; | ||
650 | addr->valid = 0; | 652 | addr->valid = 0; |
651 | list_del_rcu(&addr->list); | 653 | list_del_rcu(&addr->list); |
652 | break; | 654 | break; |
653 | } | 655 | } |
654 | } | 656 | } |
655 | spin_unlock_bh(&sctp_local_addr_lock); | 657 | spin_unlock_bh(&sctp_local_addr_lock); |
656 | if (addr && !addr->valid) | 658 | if (found) |
657 | call_rcu(&addr->rcu, sctp_local_addr_free); | 659 | call_rcu(&addr->rcu, sctp_local_addr_free); |
658 | break; | 660 | break; |
659 | } | 661 | } |