Skip to content
This repository has been archived by the owner on Jul 13, 2022. It is now read-only.

Commit

Permalink
xfrm: Workaround incompatibility of ESN and async crypto
Browse files Browse the repository at this point in the history
[ Upstream commit 3b59df46a449ec9975146d71318c4777ad086744 ]

ESN for esp is defined in RFC 4303. This RFC assumes that the
sequence number counters are always up to date. However,
this is not true if an async crypto algorithm is employed.

If the sequence number counters are not up to date on sequence
number check, we may incorrectly update the upper 32 bit of
the sequence number. This leads to a DOS.

We workaround this by comparing the upper sequence number,
(used for authentication) with the upper sequence number
computed after the async processing. We drop the packet
if these numbers are different.

To do this, we introduce a recheck function that does this
check in the ESN case.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
klassert authored and gregkh committed Oct 12, 2012
1 parent 21de4eb commit 7218add
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 1 deletion.
3 changes: 3 additions & 0 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ struct xfrm_replay {
int (*check)(struct xfrm_state *x,
struct sk_buff *skb,
__be32 net_seq);
int (*recheck)(struct xfrm_state *x,
struct sk_buff *skb,
__be32 net_seq);
void (*notify)(struct xfrm_state *x, int event);
int (*overflow)(struct xfrm_state *x, struct sk_buff *skb);
};
Expand Down
2 changes: 1 addition & 1 deletion net/xfrm/xfrm_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
/* only the first xfrm gets the encap type */
encap_type = 0;

if (async && x->repl->check(x, skb, seq)) {
if (async && x->repl->recheck(x, skb, seq)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
goto drop_unlock;
}
Expand Down
15 changes: 15 additions & 0 deletions net/xfrm/xfrm_replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,18 @@ static int xfrm_replay_check_esn(struct xfrm_state *x,
return -EINVAL;
}

static int xfrm_replay_recheck_esn(struct xfrm_state *x,
struct sk_buff *skb, __be32 net_seq)
{
if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi !=
htonl(xfrm_replay_seqhi(x, net_seq)))) {
x->stats.replay_window++;
return -EINVAL;
}

return xfrm_replay_check_esn(x, skb, net_seq);
}

static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
{
unsigned int bitnr, nr, i;
Expand Down Expand Up @@ -508,20 +520,23 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
static struct xfrm_replay xfrm_replay_legacy = {
.advance = xfrm_replay_advance,
.check = xfrm_replay_check,
.recheck = xfrm_replay_check,
.notify = xfrm_replay_notify,
.overflow = xfrm_replay_overflow,
};

static struct xfrm_replay xfrm_replay_bmp = {
.advance = xfrm_replay_advance_bmp,
.check = xfrm_replay_check_bmp,
.recheck = xfrm_replay_check_bmp,
.notify = xfrm_replay_notify_bmp,
.overflow = xfrm_replay_overflow_bmp,
};

static struct xfrm_replay xfrm_replay_esn = {
.advance = xfrm_replay_advance_esn,
.check = xfrm_replay_check_esn,
.recheck = xfrm_replay_recheck_esn,
.notify = xfrm_replay_notify_bmp,
.overflow = xfrm_replay_overflow_esn,
};
Expand Down

0 comments on commit 7218add

Please sign in to comment.