2020
2121#include <net/xfrm.h>
2222
23+ u32 xfrm_replay_seqhi (struct xfrm_state * x , __be32 net_seq )
24+ {
25+ u32 seq , seq_hi , bottom ;
26+ struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
27+
28+ if (!(x -> props .flags & XFRM_STATE_ESN ))
29+ return 0 ;
30+
31+ seq = ntohl (net_seq );
32+ seq_hi = replay_esn -> seq_hi ;
33+ bottom = replay_esn -> seq - replay_esn -> replay_window + 1 ;
34+
35+ if (likely (replay_esn -> seq >= replay_esn -> replay_window - 1 )) {
36+ /* A. same subspace */
37+ if (unlikely (seq < bottom ))
38+ seq_hi ++ ;
39+ } else {
40+ /* B. window spans two subspaces */
41+ if (unlikely (seq >= bottom ))
42+ seq_hi -- ;
43+ }
44+
45+ return seq_hi ;
46+ }
47+
2348static void xfrm_replay_notify (struct xfrm_state * x , int event )
2449{
2550 struct km_event c ;
@@ -313,6 +338,160 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
313338 x -> xflags &= ~XFRM_TIME_DEFER ;
314339}
315340
341+ static int xfrm_replay_overflow_esn (struct xfrm_state * x , struct sk_buff * skb )
342+ {
343+ int err = 0 ;
344+ struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
345+ struct net * net = xs_net (x );
346+
347+ if (x -> type -> flags & XFRM_TYPE_REPLAY_PROT ) {
348+ XFRM_SKB_CB (skb )-> seq .output .low = ++ replay_esn -> oseq ;
349+ XFRM_SKB_CB (skb )-> seq .output .hi = replay_esn -> oseq_hi ;
350+
351+ if (unlikely (replay_esn -> oseq == 0 )) {
352+ XFRM_SKB_CB (skb )-> seq .output .hi = ++ replay_esn -> oseq_hi ;
353+
354+ if (replay_esn -> oseq_hi == 0 ) {
355+ replay_esn -> oseq -- ;
356+ replay_esn -> oseq_hi -- ;
357+ xfrm_audit_state_replay_overflow (x , skb );
358+ err = - EOVERFLOW ;
359+
360+ return err ;
361+ }
362+ }
363+ if (xfrm_aevent_is_on (net ))
364+ x -> repl -> notify (x , XFRM_REPLAY_UPDATE );
365+ }
366+
367+ return err ;
368+ }
369+
370+ static int xfrm_replay_check_esn (struct xfrm_state * x ,
371+ struct sk_buff * skb , __be32 net_seq )
372+ {
373+ unsigned int bitnr , nr ;
374+ u32 diff ;
375+ struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
376+ u32 seq = ntohl (net_seq );
377+ u32 pos = (replay_esn -> seq - 1 ) % replay_esn -> replay_window ;
378+ u32 wsize = replay_esn -> replay_window ;
379+ u32 top = replay_esn -> seq ;
380+ u32 bottom = top - wsize + 1 ;
381+
382+ if (unlikely (seq == 0 && replay_esn -> seq_hi == 0 &&
383+ (replay_esn -> seq < replay_esn -> replay_window - 1 )))
384+ goto err ;
385+
386+ diff = top - seq ;
387+
388+ if (likely (top >= wsize - 1 )) {
389+ /* A. same subspace */
390+ if (likely (seq > top ) || seq < bottom )
391+ return 0 ;
392+ } else {
393+ /* B. window spans two subspaces */
394+ if (likely (seq > top && seq < bottom ))
395+ return 0 ;
396+ if (seq >= bottom )
397+ diff = ~seq + top + 1 ;
398+ }
399+
400+ if (diff >= replay_esn -> replay_window ) {
401+ x -> stats .replay_window ++ ;
402+ goto err ;
403+ }
404+
405+ if (pos >= diff ) {
406+ bitnr = (pos - diff ) % replay_esn -> replay_window ;
407+ nr = bitnr >> 5 ;
408+ bitnr = bitnr & 0x1F ;
409+ if (replay_esn -> bmp [nr ] & (1U << bitnr ))
410+ goto err_replay ;
411+ } else {
412+ bitnr = replay_esn -> replay_window - (diff - pos );
413+ nr = bitnr >> 5 ;
414+ bitnr = bitnr & 0x1F ;
415+ if (replay_esn -> bmp [nr ] & (1U << bitnr ))
416+ goto err_replay ;
417+ }
418+ return 0 ;
419+
420+ err_replay :
421+ x -> stats .replay ++ ;
422+ err :
423+ xfrm_audit_state_replay (x , skb , net_seq );
424+ return - EINVAL ;
425+ }
426+
427+ static void xfrm_replay_advance_esn (struct xfrm_state * x , __be32 net_seq )
428+ {
429+ unsigned int bitnr , nr , i ;
430+ int wrap ;
431+ u32 diff , pos , seq , seq_hi ;
432+ struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
433+
434+ if (!replay_esn -> replay_window )
435+ return ;
436+
437+ seq = ntohl (net_seq );
438+ pos = (replay_esn -> seq - 1 ) % replay_esn -> replay_window ;
439+ seq_hi = xfrm_replay_seqhi (x , net_seq );
440+ wrap = seq_hi - replay_esn -> seq_hi ;
441+
442+ if ((!wrap && seq > replay_esn -> seq ) || wrap > 0 ) {
443+ if (likely (!wrap ))
444+ diff = seq - replay_esn -> seq ;
445+ else
446+ diff = ~replay_esn -> seq + seq + 1 ;
447+
448+ if (diff < replay_esn -> replay_window ) {
449+ for (i = 1 ; i < diff ; i ++ ) {
450+ bitnr = (pos + i ) % replay_esn -> replay_window ;
451+ nr = bitnr >> 5 ;
452+ bitnr = bitnr & 0x1F ;
453+ replay_esn -> bmp [nr ] &= ~(1U << bitnr );
454+ }
455+
456+ bitnr = (pos + diff ) % replay_esn -> replay_window ;
457+ nr = bitnr >> 5 ;
458+ bitnr = bitnr & 0x1F ;
459+ replay_esn -> bmp [nr ] |= (1U << bitnr );
460+ } else {
461+ nr = replay_esn -> replay_window >> 5 ;
462+ for (i = 0 ; i <= nr ; i ++ )
463+ replay_esn -> bmp [i ] = 0 ;
464+
465+ bitnr = (pos + diff ) % replay_esn -> replay_window ;
466+ nr = bitnr >> 5 ;
467+ bitnr = bitnr & 0x1F ;
468+ replay_esn -> bmp [nr ] |= (1U << bitnr );
469+ }
470+
471+ replay_esn -> seq = seq ;
472+
473+ if (unlikely (wrap > 0 ))
474+ replay_esn -> seq_hi ++ ;
475+ } else {
476+ diff = replay_esn -> seq - seq ;
477+
478+ if (pos >= diff ) {
479+ bitnr = (pos - diff ) % replay_esn -> replay_window ;
480+ nr = bitnr >> 5 ;
481+ bitnr = bitnr & 0x1F ;
482+ replay_esn -> bmp [nr ] |= (1U << bitnr );
483+ } else {
484+ bitnr = replay_esn -> replay_window - (diff - pos );
485+ nr = bitnr >> 5 ;
486+ bitnr = bitnr & 0x1F ;
487+ replay_esn -> bmp [nr ] |= (1U << bitnr );
488+ }
489+ }
490+
491+ if (xfrm_aevent_is_on (xs_net (x )))
492+ xfrm_replay_notify (x , XFRM_REPLAY_UPDATE );
493+ }
494+
316495static struct xfrm_replay xfrm_replay_legacy = {
317496 .advance = xfrm_replay_advance ,
318497 .check = xfrm_replay_check ,
@@ -327,6 +506,13 @@ static struct xfrm_replay xfrm_replay_bmp = {
327506 .overflow = xfrm_replay_overflow_bmp ,
328507};
329508
509+ static struct xfrm_replay xfrm_replay_esn = {
510+ .advance = xfrm_replay_advance_esn ,
511+ .check = xfrm_replay_check_esn ,
512+ .notify = xfrm_replay_notify_bmp ,
513+ .overflow = xfrm_replay_overflow_esn ,
514+ };
515+
330516int xfrm_init_replay (struct xfrm_state * x )
331517{
332518 struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
@@ -336,11 +522,13 @@ int xfrm_init_replay(struct xfrm_state *x)
336522 replay_esn -> bmp_len * sizeof (__u32 ))
337523 return - EINVAL ;
338524
525+ if ((x -> props .flags & XFRM_STATE_ESN ) && x -> replay_esn )
526+ x -> repl = & xfrm_replay_esn ;
527+ else
339528 x -> repl = & xfrm_replay_bmp ;
340529 } else
341530 x -> repl = & xfrm_replay_legacy ;
342531
343-
344532 return 0 ;
345533}
346534EXPORT_SYMBOL (xfrm_init_replay );
0 commit comments