1 // SPDX-License-Identifier: GPL-2.0-only
3 * xfrm_replay.c - xfrm replay detection, derived from xfrm_state.c.
5 * Copyright (C) 2010 secunet Security Networks AG
6 * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
9 #include <linux/export.h>
12 u32
xfrm_replay_seqhi(struct xfrm_state
*x
, __be32 net_seq
)
14 u32 seq
, seq_hi
, bottom
;
15 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
17 if (!(x
->props
.flags
& XFRM_STATE_ESN
))
21 seq_hi
= replay_esn
->seq_hi
;
22 bottom
= replay_esn
->seq
- replay_esn
->replay_window
+ 1;
24 if (likely(replay_esn
->seq
>= replay_esn
->replay_window
- 1)) {
25 /* A. same subspace */
26 if (unlikely(seq
< bottom
))
29 /* B. window spans two subspaces */
30 if (unlikely(seq
>= bottom
))
36 EXPORT_SYMBOL(xfrm_replay_seqhi
);
38 static void xfrm_replay_notify(struct xfrm_state
*x
, int event
)
41 /* we send notify messages in case
42 * 1. we updated on of the sequence numbers, and the seqno difference
43 * is at least x->replay_maxdiff, in this case we also update the
44 * timeout of our timer function
45 * 2. if x->replay_maxage has elapsed since last update,
46 * and there were changes
48 * The state structure must be locked!
52 case XFRM_REPLAY_UPDATE
:
53 if (!x
->replay_maxdiff
||
54 ((x
->replay
.seq
- x
->preplay
.seq
< x
->replay_maxdiff
) &&
55 (x
->replay
.oseq
- x
->preplay
.oseq
< x
->replay_maxdiff
))) {
56 if (x
->xflags
& XFRM_TIME_DEFER
)
57 event
= XFRM_REPLAY_TIMEOUT
;
64 case XFRM_REPLAY_TIMEOUT
:
65 if (memcmp(&x
->replay
, &x
->preplay
,
66 sizeof(struct xfrm_replay_state
)) == 0) {
67 x
->xflags
|= XFRM_TIME_DEFER
;
74 memcpy(&x
->preplay
, &x
->replay
, sizeof(struct xfrm_replay_state
));
75 c
.event
= XFRM_MSG_NEWAE
;
76 c
.data
.aevent
= event
;
77 km_state_notify(x
, &c
);
79 if (x
->replay_maxage
&&
80 !mod_timer(&x
->rtimer
, jiffies
+ x
->replay_maxage
))
81 x
->xflags
&= ~XFRM_TIME_DEFER
;
84 static int xfrm_replay_overflow(struct xfrm_state
*x
, struct sk_buff
*skb
)
87 struct net
*net
= xs_net(x
);
89 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
90 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++x
->replay
.oseq
;
91 XFRM_SKB_CB(skb
)->seq
.output
.hi
= 0;
92 if (unlikely(x
->replay
.oseq
== 0)) {
94 xfrm_audit_state_replay_overflow(x
, skb
);
99 if (xfrm_aevent_is_on(net
))
100 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
106 static int xfrm_replay_check(struct xfrm_state
*x
,
107 struct sk_buff
*skb
, __be32 net_seq
)
110 u32 seq
= ntohl(net_seq
);
112 if (!x
->props
.replay_window
)
115 if (unlikely(seq
== 0))
118 if (likely(seq
> x
->replay
.seq
))
121 diff
= x
->replay
.seq
- seq
;
122 if (diff
>= x
->props
.replay_window
) {
123 x
->stats
.replay_window
++;
127 if (x
->replay
.bitmap
& (1U << diff
)) {
134 xfrm_audit_state_replay(x
, skb
, net_seq
);
138 static void xfrm_replay_advance(struct xfrm_state
*x
, __be32 net_seq
)
141 u32 seq
= ntohl(net_seq
);
143 if (!x
->props
.replay_window
)
146 if (seq
> x
->replay
.seq
) {
147 diff
= seq
- x
->replay
.seq
;
148 if (diff
< x
->props
.replay_window
)
149 x
->replay
.bitmap
= ((x
->replay
.bitmap
) << diff
) | 1;
151 x
->replay
.bitmap
= 1;
154 diff
= x
->replay
.seq
- seq
;
155 x
->replay
.bitmap
|= (1U << diff
);
158 if (xfrm_aevent_is_on(xs_net(x
)))
159 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
162 static int xfrm_replay_overflow_bmp(struct xfrm_state
*x
, struct sk_buff
*skb
)
165 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
166 struct net
*net
= xs_net(x
);
168 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
169 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++replay_esn
->oseq
;
170 XFRM_SKB_CB(skb
)->seq
.output
.hi
= 0;
171 if (unlikely(replay_esn
->oseq
== 0)) {
173 xfrm_audit_state_replay_overflow(x
, skb
);
178 if (xfrm_aevent_is_on(net
))
179 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
185 static int xfrm_replay_check_bmp(struct xfrm_state
*x
,
186 struct sk_buff
*skb
, __be32 net_seq
)
188 unsigned int bitnr
, nr
;
189 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
191 u32 seq
= ntohl(net_seq
);
192 u32 diff
= replay_esn
->seq
- seq
;
194 if (!replay_esn
->replay_window
)
197 if (unlikely(seq
== 0))
200 if (likely(seq
> replay_esn
->seq
))
203 if (diff
>= replay_esn
->replay_window
) {
204 x
->stats
.replay_window
++;
208 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
211 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
213 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
216 bitnr
= bitnr
& 0x1F;
217 if (replay_esn
->bmp
[nr
] & (1U << bitnr
))
225 xfrm_audit_state_replay(x
, skb
, net_seq
);
229 static void xfrm_replay_advance_bmp(struct xfrm_state
*x
, __be32 net_seq
)
231 unsigned int bitnr
, nr
, i
;
233 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
234 u32 seq
= ntohl(net_seq
);
237 if (!replay_esn
->replay_window
)
240 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
242 if (seq
> replay_esn
->seq
) {
243 diff
= seq
- replay_esn
->seq
;
245 if (diff
< replay_esn
->replay_window
) {
246 for (i
= 1; i
< diff
; i
++) {
247 bitnr
= (pos
+ i
) % replay_esn
->replay_window
;
249 bitnr
= bitnr
& 0x1F;
250 replay_esn
->bmp
[nr
] &= ~(1U << bitnr
);
253 nr
= (replay_esn
->replay_window
- 1) >> 5;
254 for (i
= 0; i
<= nr
; i
++)
255 replay_esn
->bmp
[i
] = 0;
258 bitnr
= (pos
+ diff
) % replay_esn
->replay_window
;
259 replay_esn
->seq
= seq
;
261 diff
= replay_esn
->seq
- seq
;
264 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
266 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
270 bitnr
= bitnr
& 0x1F;
271 replay_esn
->bmp
[nr
] |= (1U << bitnr
);
273 if (xfrm_aevent_is_on(xs_net(x
)))
274 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
277 static void xfrm_replay_notify_bmp(struct xfrm_state
*x
, int event
)
280 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
281 struct xfrm_replay_state_esn
*preplay_esn
= x
->preplay_esn
;
283 /* we send notify messages in case
284 * 1. we updated on of the sequence numbers, and the seqno difference
285 * is at least x->replay_maxdiff, in this case we also update the
286 * timeout of our timer function
287 * 2. if x->replay_maxage has elapsed since last update,
288 * and there were changes
290 * The state structure must be locked!
294 case XFRM_REPLAY_UPDATE
:
295 if (!x
->replay_maxdiff
||
296 ((replay_esn
->seq
- preplay_esn
->seq
< x
->replay_maxdiff
) &&
297 (replay_esn
->oseq
- preplay_esn
->oseq
298 < x
->replay_maxdiff
))) {
299 if (x
->xflags
& XFRM_TIME_DEFER
)
300 event
= XFRM_REPLAY_TIMEOUT
;
307 case XFRM_REPLAY_TIMEOUT
:
308 if (memcmp(x
->replay_esn
, x
->preplay_esn
,
309 xfrm_replay_state_esn_len(replay_esn
)) == 0) {
310 x
->xflags
|= XFRM_TIME_DEFER
;
317 memcpy(x
->preplay_esn
, x
->replay_esn
,
318 xfrm_replay_state_esn_len(replay_esn
));
319 c
.event
= XFRM_MSG_NEWAE
;
320 c
.data
.aevent
= event
;
321 km_state_notify(x
, &c
);
323 if (x
->replay_maxage
&&
324 !mod_timer(&x
->rtimer
, jiffies
+ x
->replay_maxage
))
325 x
->xflags
&= ~XFRM_TIME_DEFER
;
328 static void xfrm_replay_notify_esn(struct xfrm_state
*x
, int event
)
330 u32 seq_diff
, oseq_diff
;
332 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
333 struct xfrm_replay_state_esn
*preplay_esn
= x
->preplay_esn
;
335 /* we send notify messages in case
336 * 1. we updated on of the sequence numbers, and the seqno difference
337 * is at least x->replay_maxdiff, in this case we also update the
338 * timeout of our timer function
339 * 2. if x->replay_maxage has elapsed since last update,
340 * and there were changes
342 * The state structure must be locked!
346 case XFRM_REPLAY_UPDATE
:
347 if (x
->replay_maxdiff
) {
348 if (replay_esn
->seq_hi
== preplay_esn
->seq_hi
)
349 seq_diff
= replay_esn
->seq
- preplay_esn
->seq
;
351 seq_diff
= ~preplay_esn
->seq
+ replay_esn
->seq
354 if (replay_esn
->oseq_hi
== preplay_esn
->oseq_hi
)
355 oseq_diff
= replay_esn
->oseq
358 oseq_diff
= ~preplay_esn
->oseq
359 + replay_esn
->oseq
+ 1;
361 if (seq_diff
>= x
->replay_maxdiff
||
362 oseq_diff
>= x
->replay_maxdiff
)
366 if (x
->xflags
& XFRM_TIME_DEFER
)
367 event
= XFRM_REPLAY_TIMEOUT
;
373 case XFRM_REPLAY_TIMEOUT
:
374 if (memcmp(x
->replay_esn
, x
->preplay_esn
,
375 xfrm_replay_state_esn_len(replay_esn
)) == 0) {
376 x
->xflags
|= XFRM_TIME_DEFER
;
383 memcpy(x
->preplay_esn
, x
->replay_esn
,
384 xfrm_replay_state_esn_len(replay_esn
));
385 c
.event
= XFRM_MSG_NEWAE
;
386 c
.data
.aevent
= event
;
387 km_state_notify(x
, &c
);
389 if (x
->replay_maxage
&&
390 !mod_timer(&x
->rtimer
, jiffies
+ x
->replay_maxage
))
391 x
->xflags
&= ~XFRM_TIME_DEFER
;
394 static int xfrm_replay_overflow_esn(struct xfrm_state
*x
, struct sk_buff
*skb
)
397 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
398 struct net
*net
= xs_net(x
);
400 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
401 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++replay_esn
->oseq
;
402 XFRM_SKB_CB(skb
)->seq
.output
.hi
= replay_esn
->oseq_hi
;
404 if (unlikely(replay_esn
->oseq
== 0)) {
405 XFRM_SKB_CB(skb
)->seq
.output
.hi
= ++replay_esn
->oseq_hi
;
407 if (replay_esn
->oseq_hi
== 0) {
409 replay_esn
->oseq_hi
--;
410 xfrm_audit_state_replay_overflow(x
, skb
);
416 if (xfrm_aevent_is_on(net
))
417 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
423 static int xfrm_replay_check_esn(struct xfrm_state
*x
,
424 struct sk_buff
*skb
, __be32 net_seq
)
426 unsigned int bitnr
, nr
;
428 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
430 u32 seq
= ntohl(net_seq
);
431 u32 wsize
= replay_esn
->replay_window
;
432 u32 top
= replay_esn
->seq
;
433 u32 bottom
= top
- wsize
+ 1;
438 if (unlikely(seq
== 0 && replay_esn
->seq_hi
== 0 &&
439 (replay_esn
->seq
< replay_esn
->replay_window
- 1)))
444 if (likely(top
>= wsize
- 1)) {
445 /* A. same subspace */
446 if (likely(seq
> top
) || seq
< bottom
)
449 /* B. window spans two subspaces */
450 if (likely(seq
> top
&& seq
< bottom
))
453 diff
= ~seq
+ top
+ 1;
456 if (diff
>= replay_esn
->replay_window
) {
457 x
->stats
.replay_window
++;
461 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
464 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
466 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
469 bitnr
= bitnr
& 0x1F;
470 if (replay_esn
->bmp
[nr
] & (1U << bitnr
))
478 xfrm_audit_state_replay(x
, skb
, net_seq
);
482 static int xfrm_replay_recheck_esn(struct xfrm_state
*x
,
483 struct sk_buff
*skb
, __be32 net_seq
)
485 if (unlikely(XFRM_SKB_CB(skb
)->seq
.input
.hi
!=
486 htonl(xfrm_replay_seqhi(x
, net_seq
)))) {
487 x
->stats
.replay_window
++;
491 return xfrm_replay_check_esn(x
, skb
, net_seq
);
494 static void xfrm_replay_advance_esn(struct xfrm_state
*x
, __be32 net_seq
)
496 unsigned int bitnr
, nr
, i
;
498 u32 diff
, pos
, seq
, seq_hi
;
499 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
501 if (!replay_esn
->replay_window
)
504 seq
= ntohl(net_seq
);
505 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
506 seq_hi
= xfrm_replay_seqhi(x
, net_seq
);
507 wrap
= seq_hi
- replay_esn
->seq_hi
;
509 if ((!wrap
&& seq
> replay_esn
->seq
) || wrap
> 0) {
511 diff
= seq
- replay_esn
->seq
;
513 diff
= ~replay_esn
->seq
+ seq
+ 1;
515 if (diff
< replay_esn
->replay_window
) {
516 for (i
= 1; i
< diff
; i
++) {
517 bitnr
= (pos
+ i
) % replay_esn
->replay_window
;
519 bitnr
= bitnr
& 0x1F;
520 replay_esn
->bmp
[nr
] &= ~(1U << bitnr
);
523 nr
= (replay_esn
->replay_window
- 1) >> 5;
524 for (i
= 0; i
<= nr
; i
++)
525 replay_esn
->bmp
[i
] = 0;
528 bitnr
= (pos
+ diff
) % replay_esn
->replay_window
;
529 replay_esn
->seq
= seq
;
531 if (unlikely(wrap
> 0))
532 replay_esn
->seq_hi
++;
534 diff
= replay_esn
->seq
- seq
;
537 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
539 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
542 xfrm_dev_state_advance_esn(x
);
545 bitnr
= bitnr
& 0x1F;
546 replay_esn
->bmp
[nr
] |= (1U << bitnr
);
548 if (xfrm_aevent_is_on(xs_net(x
)))
549 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
552 #ifdef CONFIG_XFRM_OFFLOAD
553 static int xfrm_replay_overflow_offload(struct xfrm_state
*x
, struct sk_buff
*skb
)
556 struct net
*net
= xs_net(x
);
557 struct xfrm_offload
*xo
= xfrm_offload(skb
);
558 __u32 oseq
= x
->replay
.oseq
;
561 return xfrm_replay_overflow(x
, skb
);
563 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
564 if (!skb_is_gso(skb
)) {
565 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++oseq
;
568 XFRM_SKB_CB(skb
)->seq
.output
.low
= oseq
+ 1;
569 xo
->seq
.low
= oseq
+ 1;
570 oseq
+= skb_shinfo(skb
)->gso_segs
;
573 XFRM_SKB_CB(skb
)->seq
.output
.hi
= 0;
575 if (unlikely(oseq
< x
->replay
.oseq
)) {
576 xfrm_audit_state_replay_overflow(x
, skb
);
582 x
->replay
.oseq
= oseq
;
584 if (xfrm_aevent_is_on(net
))
585 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
591 static int xfrm_replay_overflow_offload_bmp(struct xfrm_state
*x
, struct sk_buff
*skb
)
594 struct xfrm_offload
*xo
= xfrm_offload(skb
);
595 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
596 struct net
*net
= xs_net(x
);
597 __u32 oseq
= replay_esn
->oseq
;
600 return xfrm_replay_overflow_bmp(x
, skb
);
602 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
603 if (!skb_is_gso(skb
)) {
604 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++oseq
;
607 XFRM_SKB_CB(skb
)->seq
.output
.low
= oseq
+ 1;
608 xo
->seq
.low
= oseq
+ 1;
609 oseq
+= skb_shinfo(skb
)->gso_segs
;
612 XFRM_SKB_CB(skb
)->seq
.output
.hi
= 0;
614 if (unlikely(oseq
< replay_esn
->oseq
)) {
615 xfrm_audit_state_replay_overflow(x
, skb
);
620 replay_esn
->oseq
= oseq
;
623 if (xfrm_aevent_is_on(net
))
624 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
630 static int xfrm_replay_overflow_offload_esn(struct xfrm_state
*x
, struct sk_buff
*skb
)
633 struct xfrm_offload
*xo
= xfrm_offload(skb
);
634 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
635 struct net
*net
= xs_net(x
);
636 __u32 oseq
= replay_esn
->oseq
;
637 __u32 oseq_hi
= replay_esn
->oseq_hi
;
640 return xfrm_replay_overflow_esn(x
, skb
);
642 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
643 if (!skb_is_gso(skb
)) {
644 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++oseq
;
645 XFRM_SKB_CB(skb
)->seq
.output
.hi
= oseq_hi
;
647 xo
->seq
.hi
= oseq_hi
;
649 XFRM_SKB_CB(skb
)->seq
.output
.low
= oseq
+ 1;
650 XFRM_SKB_CB(skb
)->seq
.output
.hi
= oseq_hi
;
651 xo
->seq
.low
= oseq
+ 1;
652 xo
->seq
.hi
= oseq_hi
;
653 oseq
+= skb_shinfo(skb
)->gso_segs
;
656 if (unlikely(oseq
< replay_esn
->oseq
)) {
657 XFRM_SKB_CB(skb
)->seq
.output
.hi
= ++oseq_hi
;
658 xo
->seq
.hi
= oseq_hi
;
659 replay_esn
->oseq_hi
= oseq_hi
;
660 if (replay_esn
->oseq_hi
== 0) {
662 replay_esn
->oseq_hi
--;
663 xfrm_audit_state_replay_overflow(x
, skb
);
670 replay_esn
->oseq
= oseq
;
672 if (xfrm_aevent_is_on(net
))
673 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
679 static const struct xfrm_replay xfrm_replay_legacy
= {
680 .advance
= xfrm_replay_advance
,
681 .check
= xfrm_replay_check
,
682 .recheck
= xfrm_replay_check
,
683 .notify
= xfrm_replay_notify
,
684 .overflow
= xfrm_replay_overflow_offload
,
687 static const struct xfrm_replay xfrm_replay_bmp
= {
688 .advance
= xfrm_replay_advance_bmp
,
689 .check
= xfrm_replay_check_bmp
,
690 .recheck
= xfrm_replay_check_bmp
,
691 .notify
= xfrm_replay_notify_bmp
,
692 .overflow
= xfrm_replay_overflow_offload_bmp
,
695 static const struct xfrm_replay xfrm_replay_esn
= {
696 .advance
= xfrm_replay_advance_esn
,
697 .check
= xfrm_replay_check_esn
,
698 .recheck
= xfrm_replay_recheck_esn
,
699 .notify
= xfrm_replay_notify_esn
,
700 .overflow
= xfrm_replay_overflow_offload_esn
,
703 static const struct xfrm_replay xfrm_replay_legacy
= {
704 .advance
= xfrm_replay_advance
,
705 .check
= xfrm_replay_check
,
706 .recheck
= xfrm_replay_check
,
707 .notify
= xfrm_replay_notify
,
708 .overflow
= xfrm_replay_overflow
,
711 static const struct xfrm_replay xfrm_replay_bmp
= {
712 .advance
= xfrm_replay_advance_bmp
,
713 .check
= xfrm_replay_check_bmp
,
714 .recheck
= xfrm_replay_check_bmp
,
715 .notify
= xfrm_replay_notify_bmp
,
716 .overflow
= xfrm_replay_overflow_bmp
,
719 static const struct xfrm_replay xfrm_replay_esn
= {
720 .advance
= xfrm_replay_advance_esn
,
721 .check
= xfrm_replay_check_esn
,
722 .recheck
= xfrm_replay_recheck_esn
,
723 .notify
= xfrm_replay_notify_esn
,
724 .overflow
= xfrm_replay_overflow_esn
,
728 int xfrm_init_replay(struct xfrm_state
*x
)
730 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
733 if (replay_esn
->replay_window
>
734 replay_esn
->bmp_len
* sizeof(__u32
) * 8)
737 if (x
->props
.flags
& XFRM_STATE_ESN
) {
738 if (replay_esn
->replay_window
== 0)
740 x
->repl
= &xfrm_replay_esn
;
742 x
->repl
= &xfrm_replay_bmp
;
745 x
->repl
= &xfrm_replay_legacy
;
750 EXPORT_SYMBOL(xfrm_init_replay
);