diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2013-10-08 04:49:45 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2013-10-08 04:49:45 -0400 |
commit | e7d8f6cb2f8735693396872f4608bbe305e8baee (patch) | |
tree | ec1e047b8f4a584cea14b3b9dc876b7caf3c5851 /net/xfrm | |
parent | cd808fc9a6c7cd3a4311d9d2cffc4adbeaef5f6c (diff) |
xfrm: Add refcount handling to queued policies
We need to ensure that policies can't go away as long as the hold timer
is armed, so take a refcont when we arm the timer and drop one if we
delete it.
Bug was introduced with git commit a0073fe18 ("xfrm: Add a state
resolution packet queue")
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 24 |
1 files changed, 17 insertions, 7 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index ed38d5d81f9e..5f9be976770e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -334,7 +334,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
334 | 334 | ||
335 | atomic_inc(&policy->genid); | 335 | atomic_inc(&policy->genid); |
336 | 336 | ||
337 | del_timer(&policy->polq.hold_timer); | 337 | if (del_timer(&policy->polq.hold_timer)) |
338 | xfrm_pol_put(policy); | ||
338 | xfrm_queue_purge(&policy->polq.hold_queue); | 339 | xfrm_queue_purge(&policy->polq.hold_queue); |
339 | 340 | ||
340 | if (del_timer(&policy->timer)) | 341 | if (del_timer(&policy->timer)) |
@@ -589,7 +590,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old, | |||
589 | 590 | ||
590 | spin_lock_bh(&pq->hold_queue.lock); | 591 | spin_lock_bh(&pq->hold_queue.lock); |
591 | skb_queue_splice_init(&pq->hold_queue, &list); | 592 | skb_queue_splice_init(&pq->hold_queue, &list); |
592 | del_timer(&pq->hold_timer); | 593 | if (del_timer(&pq->hold_timer)) |
594 | xfrm_pol_put(old); | ||
593 | spin_unlock_bh(&pq->hold_queue.lock); | 595 | spin_unlock_bh(&pq->hold_queue.lock); |
594 | 596 | ||
595 | if (skb_queue_empty(&list)) | 597 | if (skb_queue_empty(&list)) |
@@ -600,7 +602,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old, | |||
600 | spin_lock_bh(&pq->hold_queue.lock); | 602 | spin_lock_bh(&pq->hold_queue.lock); |
601 | skb_queue_splice(&list, &pq->hold_queue); | 603 | skb_queue_splice(&list, &pq->hold_queue); |
602 | pq->timeout = XFRM_QUEUE_TMO_MIN; | 604 | pq->timeout = XFRM_QUEUE_TMO_MIN; |
603 | mod_timer(&pq->hold_timer, jiffies); | 605 | if (!mod_timer(&pq->hold_timer, jiffies)) |
606 | xfrm_pol_hold(new); | ||
604 | spin_unlock_bh(&pq->hold_queue.lock); | 607 | spin_unlock_bh(&pq->hold_queue.lock); |
605 | } | 608 | } |
606 | 609 | ||
@@ -1787,8 +1790,9 @@ static void xfrm_policy_queue_process(unsigned long arg) | |||
1787 | goto purge_queue; | 1790 | goto purge_queue; |
1788 | 1791 | ||
1789 | pq->timeout = pq->timeout << 1; | 1792 | pq->timeout = pq->timeout << 1; |
1790 | mod_timer(&pq->hold_timer, jiffies + pq->timeout); | 1793 | if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout)) |
1791 | return; | 1794 | xfrm_pol_hold(pol); |
1795 | goto out; | ||
1792 | } | 1796 | } |
1793 | 1797 | ||
1794 | dst_release(dst); | 1798 | dst_release(dst); |
@@ -1819,11 +1823,14 @@ static void xfrm_policy_queue_process(unsigned long arg) | |||
1819 | err = dst_output(skb); | 1823 | err = dst_output(skb); |
1820 | } | 1824 | } |
1821 | 1825 | ||
1826 | out: | ||
1827 | xfrm_pol_put(pol); | ||
1822 | return; | 1828 | return; |
1823 | 1829 | ||
1824 | purge_queue: | 1830 | purge_queue: |
1825 | pq->timeout = 0; | 1831 | pq->timeout = 0; |
1826 | xfrm_queue_purge(&pq->hold_queue); | 1832 | xfrm_queue_purge(&pq->hold_queue); |
1833 | xfrm_pol_put(pol); | ||
1827 | } | 1834 | } |
1828 | 1835 | ||
1829 | static int xdst_queue_output(struct sk_buff *skb) | 1836 | static int xdst_queue_output(struct sk_buff *skb) |
@@ -1831,7 +1838,8 @@ static int xdst_queue_output(struct sk_buff *skb) | |||
1831 | unsigned long sched_next; | 1838 | unsigned long sched_next; |
1832 | struct dst_entry *dst = skb_dst(skb); | 1839 | struct dst_entry *dst = skb_dst(skb); |
1833 | struct xfrm_dst *xdst = (struct xfrm_dst *) dst; | 1840 | struct xfrm_dst *xdst = (struct xfrm_dst *) dst; |
1834 | struct xfrm_policy_queue *pq = &xdst->pols[0]->polq; | 1841 | struct xfrm_policy *pol = xdst->pols[0]; |
1842 | struct xfrm_policy_queue *pq = &pol->polq; | ||
1835 | 1843 | ||
1836 | if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) { | 1844 | if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) { |
1837 | kfree_skb(skb); | 1845 | kfree_skb(skb); |
@@ -1850,10 +1858,12 @@ static int xdst_queue_output(struct sk_buff *skb) | |||
1850 | if (del_timer(&pq->hold_timer)) { | 1858 | if (del_timer(&pq->hold_timer)) { |
1851 | if (time_before(pq->hold_timer.expires, sched_next)) | 1859 | if (time_before(pq->hold_timer.expires, sched_next)) |
1852 | sched_next = pq->hold_timer.expires; | 1860 | sched_next = pq->hold_timer.expires; |
1861 | xfrm_pol_put(pol); | ||
1853 | } | 1862 | } |
1854 | 1863 | ||
1855 | __skb_queue_tail(&pq->hold_queue, skb); | 1864 | __skb_queue_tail(&pq->hold_queue, skb); |
1856 | mod_timer(&pq->hold_timer, sched_next); | 1865 | if (!mod_timer(&pq->hold_timer, sched_next)) |
1866 | xfrm_pol_hold(pol); | ||
1857 | 1867 | ||
1858 | spin_unlock_bh(&pq->hold_queue.lock); | 1868 | spin_unlock_bh(&pq->hold_queue.lock); |
1859 | 1869 | ||