forked from Minki/linux
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== 1) We used the wrong netlink attribute to verify the lenght of the replay window on async events. Fix this by using the right netlink attribute. 2) Policy lookups can not match the output interface on forwarding. Add the needed informations to the flow informations. 3) We update the pmtu when we receive a ICMPV6_DEST_UNREACH message on IPsec with ipv6. This is wrong and leads to strange fragmented packets, only ICMPV6_PKT_TOOBIG messages should update the pmtu. Fix this by removing the ICMPV6_DEST_UNREACH check from the IPsec protocol error handlers. 4) The legacy IPsec anti replay mechanism supports anti replay windows up to 32 packets. If a user requests for a bigger anti replay window, we use 32 packets but pretend that we use the requested window size. Fix from Fan Du. 5) If asynchronous events are enabled and replay_maxdiff is set to zero, we generate an async event for every received packet instead of checking whether a timeout occurred. Fix from Thomas Egerer. 6) Policies need a refcount when the state resolution timer is armed. Otherwise the timer can fire after the policy is deleted. 7) We might dreference a NULL pointer if the hold_queue is empty, add a check to avoid this. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f606385068
@ -107,6 +107,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
|
||||
|
||||
memset(fl4, 0, sizeof(struct flowi4));
|
||||
fl4->flowi4_mark = skb->mark;
|
||||
fl4->flowi4_oif = skb_dst(skb)->dev->ifindex;
|
||||
|
||||
if (!ip_is_fragment(iph)) {
|
||||
switch (iph->protocol) {
|
||||
|
@ -618,8 +618,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
|
||||
struct xfrm_state *x;
|
||||
|
||||
if (type != ICMPV6_DEST_UNREACH &&
|
||||
type != ICMPV6_PKT_TOOBIG &&
|
||||
if (type != ICMPV6_PKT_TOOBIG &&
|
||||
type != NDISC_REDIRECT)
|
||||
return;
|
||||
|
||||
|
@ -436,8 +436,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset);
|
||||
struct xfrm_state *x;
|
||||
|
||||
if (type != ICMPV6_DEST_UNREACH &&
|
||||
type != ICMPV6_PKT_TOOBIG &&
|
||||
if (type != ICMPV6_PKT_TOOBIG &&
|
||||
type != NDISC_REDIRECT)
|
||||
return;
|
||||
|
||||
|
@ -64,8 +64,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
(struct ip_comp_hdr *)(skb->data + offset);
|
||||
struct xfrm_state *x;
|
||||
|
||||
if (type != ICMPV6_DEST_UNREACH &&
|
||||
type != ICMPV6_PKT_TOOBIG &&
|
||||
if (type != ICMPV6_PKT_TOOBIG &&
|
||||
type != NDISC_REDIRECT)
|
||||
return;
|
||||
|
||||
|
@ -138,6 +138,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
|
||||
|
||||
memset(fl6, 0, sizeof(struct flowi6));
|
||||
fl6->flowi6_mark = skb->mark;
|
||||
fl6->flowi6_oif = skb_dst(skb)->dev->ifindex;
|
||||
|
||||
fl6->daddr = reverse ? hdr->saddr : hdr->daddr;
|
||||
fl6->saddr = reverse ? hdr->daddr : hdr->saddr;
|
||||
|
@ -1098,7 +1098,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
|
||||
|
||||
x->id.proto = proto;
|
||||
x->id.spi = sa->sadb_sa_spi;
|
||||
x->props.replay_window = sa->sadb_sa_replay;
|
||||
x->props.replay_window = min_t(unsigned int, sa->sadb_sa_replay,
|
||||
(sizeof(x->replay.bitmap) * 8));
|
||||
if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN)
|
||||
x->props.flags |= XFRM_STATE_NOECN;
|
||||
if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP)
|
||||
|
@ -334,7 +334,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy)
|
||||
|
||||
atomic_inc(&policy->genid);
|
||||
|
||||
del_timer(&policy->polq.hold_timer);
|
||||
if (del_timer(&policy->polq.hold_timer))
|
||||
xfrm_pol_put(policy);
|
||||
xfrm_queue_purge(&policy->polq.hold_queue);
|
||||
|
||||
if (del_timer(&policy->timer))
|
||||
@ -589,7 +590,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
|
||||
|
||||
spin_lock_bh(&pq->hold_queue.lock);
|
||||
skb_queue_splice_init(&pq->hold_queue, &list);
|
||||
del_timer(&pq->hold_timer);
|
||||
if (del_timer(&pq->hold_timer))
|
||||
xfrm_pol_put(old);
|
||||
spin_unlock_bh(&pq->hold_queue.lock);
|
||||
|
||||
if (skb_queue_empty(&list))
|
||||
@ -600,7 +602,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
|
||||
spin_lock_bh(&pq->hold_queue.lock);
|
||||
skb_queue_splice(&list, &pq->hold_queue);
|
||||
pq->timeout = XFRM_QUEUE_TMO_MIN;
|
||||
mod_timer(&pq->hold_timer, jiffies);
|
||||
if (!mod_timer(&pq->hold_timer, jiffies))
|
||||
xfrm_pol_hold(new);
|
||||
spin_unlock_bh(&pq->hold_queue.lock);
|
||||
}
|
||||
|
||||
@ -1769,6 +1772,10 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
||||
|
||||
spin_lock(&pq->hold_queue.lock);
|
||||
skb = skb_peek(&pq->hold_queue);
|
||||
if (!skb) {
|
||||
spin_unlock(&pq->hold_queue.lock);
|
||||
goto out;
|
||||
}
|
||||
dst = skb_dst(skb);
|
||||
sk = skb->sk;
|
||||
xfrm_decode_session(skb, &fl, dst->ops->family);
|
||||
@ -1787,8 +1794,9 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
||||
goto purge_queue;
|
||||
|
||||
pq->timeout = pq->timeout << 1;
|
||||
mod_timer(&pq->hold_timer, jiffies + pq->timeout);
|
||||
return;
|
||||
if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout))
|
||||
xfrm_pol_hold(pol);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dst_release(dst);
|
||||
@ -1819,11 +1827,14 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
||||
err = dst_output(skb);
|
||||
}
|
||||
|
||||
out:
|
||||
xfrm_pol_put(pol);
|
||||
return;
|
||||
|
||||
purge_queue:
|
||||
pq->timeout = 0;
|
||||
xfrm_queue_purge(&pq->hold_queue);
|
||||
xfrm_pol_put(pol);
|
||||
}
|
||||
|
||||
static int xdst_queue_output(struct sk_buff *skb)
|
||||
@ -1831,7 +1842,8 @@ static int xdst_queue_output(struct sk_buff *skb)
|
||||
unsigned long sched_next;
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
|
||||
struct xfrm_policy_queue *pq = &xdst->pols[0]->polq;
|
||||
struct xfrm_policy *pol = xdst->pols[0];
|
||||
struct xfrm_policy_queue *pq = &pol->polq;
|
||||
|
||||
if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) {
|
||||
kfree_skb(skb);
|
||||
@ -1850,10 +1862,12 @@ static int xdst_queue_output(struct sk_buff *skb)
|
||||
if (del_timer(&pq->hold_timer)) {
|
||||
if (time_before(pq->hold_timer.expires, sched_next))
|
||||
sched_next = pq->hold_timer.expires;
|
||||
xfrm_pol_put(pol);
|
||||
}
|
||||
|
||||
__skb_queue_tail(&pq->hold_queue, skb);
|
||||
mod_timer(&pq->hold_timer, sched_next);
|
||||
if (!mod_timer(&pq->hold_timer, sched_next))
|
||||
xfrm_pol_hold(pol);
|
||||
|
||||
spin_unlock_bh(&pq->hold_queue.lock);
|
||||
|
||||
|
@ -61,9 +61,9 @@ static void xfrm_replay_notify(struct xfrm_state *x, int event)
|
||||
|
||||
switch (event) {
|
||||
case XFRM_REPLAY_UPDATE:
|
||||
if (x->replay_maxdiff &&
|
||||
(x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
|
||||
(x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
|
||||
if (!x->replay_maxdiff ||
|
||||
((x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
|
||||
(x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))) {
|
||||
if (x->xflags & XFRM_TIME_DEFER)
|
||||
event = XFRM_REPLAY_TIMEOUT;
|
||||
else
|
||||
@ -129,8 +129,7 @@ static int xfrm_replay_check(struct xfrm_state *x,
|
||||
return 0;
|
||||
|
||||
diff = x->replay.seq - seq;
|
||||
if (diff >= min_t(unsigned int, x->props.replay_window,
|
||||
sizeof(x->replay.bitmap) * 8)) {
|
||||
if (diff >= x->props.replay_window) {
|
||||
x->stats.replay_window++;
|
||||
goto err;
|
||||
}
|
||||
@ -302,9 +301,10 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
|
||||
|
||||
switch (event) {
|
||||
case XFRM_REPLAY_UPDATE:
|
||||
if (x->replay_maxdiff &&
|
||||
(replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
|
||||
(replay_esn->oseq - preplay_esn->oseq < x->replay_maxdiff)) {
|
||||
if (!x->replay_maxdiff ||
|
||||
((replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
|
||||
(replay_esn->oseq - preplay_esn->oseq
|
||||
< x->replay_maxdiff))) {
|
||||
if (x->xflags & XFRM_TIME_DEFER)
|
||||
event = XFRM_REPLAY_TIMEOUT;
|
||||
else
|
||||
@ -353,28 +353,30 @@ static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
|
||||
|
||||
switch (event) {
|
||||
case XFRM_REPLAY_UPDATE:
|
||||
if (!x->replay_maxdiff)
|
||||
break;
|
||||
|
||||
if (replay_esn->seq_hi == preplay_esn->seq_hi)
|
||||
seq_diff = replay_esn->seq - preplay_esn->seq;
|
||||
else
|
||||
seq_diff = ~preplay_esn->seq + replay_esn->seq + 1;
|
||||
|
||||
if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
|
||||
oseq_diff = replay_esn->oseq - preplay_esn->oseq;
|
||||
else
|
||||
oseq_diff = ~preplay_esn->oseq + replay_esn->oseq + 1;
|
||||
|
||||
if (seq_diff < x->replay_maxdiff &&
|
||||
oseq_diff < x->replay_maxdiff) {
|
||||
|
||||
if (x->xflags & XFRM_TIME_DEFER)
|
||||
event = XFRM_REPLAY_TIMEOUT;
|
||||
if (x->replay_maxdiff) {
|
||||
if (replay_esn->seq_hi == preplay_esn->seq_hi)
|
||||
seq_diff = replay_esn->seq - preplay_esn->seq;
|
||||
else
|
||||
return;
|
||||
seq_diff = ~preplay_esn->seq + replay_esn->seq
|
||||
+ 1;
|
||||
|
||||
if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
|
||||
oseq_diff = replay_esn->oseq
|
||||
- preplay_esn->oseq;
|
||||
else
|
||||
oseq_diff = ~preplay_esn->oseq
|
||||
+ replay_esn->oseq + 1;
|
||||
|
||||
if (seq_diff >= x->replay_maxdiff ||
|
||||
oseq_diff >= x->replay_maxdiff)
|
||||
break;
|
||||
}
|
||||
|
||||
if (x->xflags & XFRM_TIME_DEFER)
|
||||
event = XFRM_REPLAY_TIMEOUT;
|
||||
else
|
||||
return;
|
||||
|
||||
break;
|
||||
|
||||
case XFRM_REPLAY_TIMEOUT:
|
||||
|
@ -446,7 +446,8 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *
|
||||
memcpy(&x->sel, &p->sel, sizeof(x->sel));
|
||||
memcpy(&x->lft, &p->lft, sizeof(x->lft));
|
||||
x->props.mode = p->mode;
|
||||
x->props.replay_window = p->replay_window;
|
||||
x->props.replay_window = min_t(unsigned int, p->replay_window,
|
||||
sizeof(x->replay.bitmap) * 8);
|
||||
x->props.reqid = p->reqid;
|
||||
x->props.family = p->family;
|
||||
memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
|
||||
@ -1856,7 +1857,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (x->km.state != XFRM_STATE_VALID)
|
||||
goto out;
|
||||
|
||||
err = xfrm_replay_verify_len(x->replay_esn, rp);
|
||||
err = xfrm_replay_verify_len(x->replay_esn, re);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user