Skip to content

Commit

Permalink
[SCTP]: Fix local_addr deletions during list traversals.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Vlad Yasevich <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
illogict authored and davem330 committed Mar 12, 2008
1 parent b2211a3 commit 2262621
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 3 deletions.
4 changes: 3 additions & 1 deletion net/sctp/bind_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,20 +209,22 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
{
struct sctp_sockaddr_entry *addr, *temp;
int found = 0;

/* We hold the socket lock when calling this function,
* and that acts as a writer synchronizing lock.
*/
list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
/* Found the exact match. */
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
break;
}
}

if (addr && !addr->valid) {
if (found) {
call_rcu(&addr->rcu, sctp_local_addr_free);
SCTP_DBG_OBJCNT_DEC(addr);
return 0;
Expand Down
4 changes: 3 additions & 1 deletion net/sctp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
struct sctp_sockaddr_entry *addr = NULL;
struct sctp_sockaddr_entry *temp;
int found = 0;

switch (ev) {
case NETDEV_UP:
Expand All @@ -111,13 +112,14 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
&sctp_local_addr_list, list) {
if (ipv6_addr_equal(&addr->a.v6.sin6_addr,
&ifa->addr)) {
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
break;
}
}
spin_unlock_bh(&sctp_local_addr_lock);
if (addr && !addr->valid)
if (found)
call_rcu(&addr->rcu, sctp_local_addr_free);
break;
}
Expand Down
4 changes: 3 additions & 1 deletion net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
struct sctp_sockaddr_entry *addr = NULL;
struct sctp_sockaddr_entry *temp;
int found = 0;

switch (ev) {
case NETDEV_UP:
Expand All @@ -647,13 +648,14 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
list_for_each_entry_safe(addr, temp,
&sctp_local_addr_list, list) {
if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) {
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
break;
}
}
spin_unlock_bh(&sctp_local_addr_lock);
if (addr && !addr->valid)
if (found)
call_rcu(&addr->rcu, sctp_local_addr_free);
break;
}
Expand Down

0 comments on commit 2262621

Please sign in to comment.