Commit 3b59df46a449ec9975146d71318c4777ad086744

Authored by Steffen Klassert
Committed by David S. Miller
1 parent 37159ef2c1

xfrm: Workaround incompatibility of ESN and async crypto

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>

Showing 3 changed files with 19 additions and 1 deletions Side-by-side Diff

... ... @@ -273,6 +273,9 @@
273 273 int (*check)(struct xfrm_state *x,
274 274 struct sk_buff *skb,
275 275 __be32 net_seq);
  276 + int (*recheck)(struct xfrm_state *x,
  277 + struct sk_buff *skb,
  278 + __be32 net_seq);
276 279 void (*notify)(struct xfrm_state *x, int event);
277 280 int (*overflow)(struct xfrm_state *x, struct sk_buff *skb);
278 281 };
net/xfrm/xfrm_input.c
... ... @@ -212,7 +212,7 @@
212 212 /* only the first xfrm gets the encap type */
213 213 encap_type = 0;
214 214  
215   - if (async && x->repl->check(x, skb, seq)) {
  215 + if (async && x->repl->recheck(x, skb, seq)) {
216 216 XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
217 217 goto drop_unlock;
218 218 }
net/xfrm/xfrm_replay.c
... ... @@ -420,6 +420,18 @@
420 420 return -EINVAL;
421 421 }
422 422  
  423 +static int xfrm_replay_recheck_esn(struct xfrm_state *x,
  424 + struct sk_buff *skb, __be32 net_seq)
  425 +{
  426 + if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi !=
  427 + htonl(xfrm_replay_seqhi(x, net_seq)))) {
  428 + x->stats.replay_window++;
  429 + return -EINVAL;
  430 + }
  431 +
  432 + return xfrm_replay_check_esn(x, skb, net_seq);
  433 +}
  434 +
423 435 static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
424 436 {
425 437 unsigned int bitnr, nr, i;
... ... @@ -479,6 +491,7 @@
479 491 static struct xfrm_replay xfrm_replay_legacy = {
480 492 .advance = xfrm_replay_advance,
481 493 .check = xfrm_replay_check,
  494 + .recheck = xfrm_replay_check,
482 495 .notify = xfrm_replay_notify,
483 496 .overflow = xfrm_replay_overflow,
484 497 };
... ... @@ -486,6 +499,7 @@
486 499 static struct xfrm_replay xfrm_replay_bmp = {
487 500 .advance = xfrm_replay_advance_bmp,
488 501 .check = xfrm_replay_check_bmp,
  502 + .recheck = xfrm_replay_check_bmp,
489 503 .notify = xfrm_replay_notify_bmp,
490 504 .overflow = xfrm_replay_overflow_bmp,
491 505 };
... ... @@ -493,6 +507,7 @@
493 507 static struct xfrm_replay xfrm_replay_esn = {
494 508 .advance = xfrm_replay_advance_esn,
495 509 .check = xfrm_replay_check_esn,
  510 + .recheck = xfrm_replay_recheck_esn,
496 511 .notify = xfrm_replay_notify_bmp,
497 512 .overflow = xfrm_replay_overflow_esn,
498 513 };