[IPVS]: Close race conditions on ip_vs_conn_tab list modification

In an smp system, it is possible for an connection timer to expire, calling
ip_vs_conn_expire while the connection table is being flushed, before
ct_write_lock_bh is acquired.

Since the list iterator loop in ip_vs_con_flush releases and re-acquires the
spinlock (even though it doesn't re-enable softirqs), it is possible for the
expiration function to modify the connection list, while it is being traversed
in ip_vs_conn_flush.

The result is that the next pointer gets set to NULL, and subsequently
dereferenced, resulting in an oops.

Signed-off-by: Neil Horman <nhorman@redhat.com>
Acked-by: JulianAnastasov
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Neil Horman and committed by David S. Miller fb3d8949 689be439

+4 -21
+4 -21
net/ipv4/ipvs/ip_vs_conn.c
··· 548 548 { 549 549 if (del_timer(&cp->timer)) 550 550 mod_timer(&cp->timer, jiffies); 551 - __ip_vs_conn_put(cp); 552 551 } 553 552 554 553 ··· 763 764 { 764 765 int idx; 765 766 struct ip_vs_conn *cp; 766 - struct ip_vs_conn *ct; 767 767 768 768 /* 769 769 * Randomly scan 1/32 of the whole table every second ··· 799 801 continue; 800 802 } 801 803 802 - /* 803 - * Drop the entry, and drop its ct if not referenced 804 - */ 805 - atomic_inc(&cp->refcnt); 806 - ct_write_unlock(hash); 807 - 808 - if ((ct = cp->control)) 809 - atomic_inc(&ct->refcnt); 810 804 IP_VS_DBG(4, "del connection\n"); 811 805 ip_vs_conn_expire_now(cp); 812 - if (ct) { 806 + if (cp->control) { 813 807 IP_VS_DBG(4, "del conn template\n"); 814 - ip_vs_conn_expire_now(ct); 808 + ip_vs_conn_expire_now(cp->control); 815 809 } 816 - ct_write_lock(hash); 817 810 } 818 811 ct_write_unlock(hash); 819 812 } ··· 818 829 { 819 830 int idx; 820 831 struct ip_vs_conn *cp; 821 - struct ip_vs_conn *ct; 822 832 823 833 flush_again: 824 834 for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) { ··· 827 839 ct_write_lock_bh(idx); 828 840 829 841 list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) { 830 - atomic_inc(&cp->refcnt); 831 - ct_write_unlock(idx); 832 842 833 - if ((ct = cp->control)) 834 - atomic_inc(&ct->refcnt); 835 843 IP_VS_DBG(4, "del connection\n"); 836 844 ip_vs_conn_expire_now(cp); 837 - if (ct) { 845 + if (cp->control) { 838 846 IP_VS_DBG(4, "del conn template\n"); 839 - ip_vs_conn_expire_now(ct); 847 + ip_vs_conn_expire_now(cp->control); 840 848 } 841 - ct_write_lock(idx); 842 849 } 843 850 ct_write_unlock_bh(idx); 844 851 }