Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22626216 authored by Chidambar 'ilLogict' Zinnoury's avatar Chidambar 'ilLogict' Zinnoury Committed by David S. Miller
Browse files

[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: default avatarChidambar 'ilLogict' Zinnoury <illogict@online.fr>
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b2211a36
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -209,6 +209,7 @@ 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.
@@ -216,13 +217,14 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
	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;
+3 −1
Original line number Diff line number Diff line
@@ -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:
@@ -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;
	}
+3 −1
Original line number Diff line number Diff line
@@ -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:
@@ -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;
	}