~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/xfrm/xfrm_replay.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * xfrm_replay.c - xfrm replay detection, derived from xfrm_state.c.
  4  *
  5  * Copyright (C) 2010 secunet Security Networks AG
  6  * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
  7  */
  8 
  9 #include <linux/export.h>
 10 #include <net/xfrm.h>
 11 
 12 u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq)
 13 {
 14         u32 seq, seq_hi, bottom;
 15         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 16 
 17         if (!(x->props.flags & XFRM_STATE_ESN))
 18                 return 0;
 19 
 20         seq = ntohl(net_seq);
 21         seq_hi = replay_esn->seq_hi;
 22         bottom = replay_esn->seq - replay_esn->replay_window + 1;
 23 
 24         if (likely(replay_esn->seq >= replay_esn->replay_window - 1)) {
 25                 /* A. same subspace */
 26                 if (unlikely(seq < bottom))
 27                         seq_hi++;
 28         } else {
 29                 /* B. window spans two subspaces */
 30                 if (unlikely(seq >= bottom))
 31                         seq_hi--;
 32         }
 33 
 34         return seq_hi;
 35 }
 36 EXPORT_SYMBOL(xfrm_replay_seqhi);
 37 
 38 static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event);
 39 static void xfrm_replay_notify_esn(struct xfrm_state *x, int event);
 40 
 41 void xfrm_replay_notify(struct xfrm_state *x, int event)
 42 {
 43         struct km_event c;
 44         /* we send notify messages in case
 45          *  1. we updated on of the sequence numbers, and the seqno difference
 46          *     is at least x->replay_maxdiff, in this case we also update the
 47          *     timeout of our timer function
 48          *  2. if x->replay_maxage has elapsed since last update,
 49          *     and there were changes
 50          *
 51          *  The state structure must be locked!
 52          */
 53 
 54         switch (x->repl_mode) {
 55         case XFRM_REPLAY_MODE_LEGACY:
 56                 break;
 57         case XFRM_REPLAY_MODE_BMP:
 58                 xfrm_replay_notify_bmp(x, event);
 59                 return;
 60         case XFRM_REPLAY_MODE_ESN:
 61                 xfrm_replay_notify_esn(x, event);
 62                 return;
 63         }
 64 
 65         switch (event) {
 66         case XFRM_REPLAY_UPDATE:
 67                 if (!x->replay_maxdiff ||
 68                     ((x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
 69                     (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))) {
 70                         if (x->xflags & XFRM_TIME_DEFER)
 71                                 event = XFRM_REPLAY_TIMEOUT;
 72                         else
 73                                 return;
 74                 }
 75 
 76                 break;
 77 
 78         case XFRM_REPLAY_TIMEOUT:
 79                 if (memcmp(&x->replay, &x->preplay,
 80                            sizeof(struct xfrm_replay_state)) == 0) {
 81                         x->xflags |= XFRM_TIME_DEFER;
 82                         return;
 83                 }
 84 
 85                 break;
 86         }
 87 
 88         memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
 89         c.event = XFRM_MSG_NEWAE;
 90         c.data.aevent = event;
 91         km_state_notify(x, &c);
 92 
 93         if (x->replay_maxage &&
 94             !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
 95                 x->xflags &= ~XFRM_TIME_DEFER;
 96 }
 97 
 98 static int __xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
 99 {
100         int err = 0;
101         struct net *net = xs_net(x);
102 
103         if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
104                 XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq;
105                 XFRM_SKB_CB(skb)->seq.output.hi = 0;
106                 if (unlikely(x->replay.oseq == 0) &&
107                     !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
108                         x->replay.oseq--;
109                         xfrm_audit_state_replay_overflow(x, skb);
110                         err = -EOVERFLOW;
111 
112                         return err;
113                 }
114                 if (xfrm_aevent_is_on(net))
115                         xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
116         }
117 
118         return err;
119 }
120 
121 static int xfrm_replay_check_legacy(struct xfrm_state *x,
122                                     struct sk_buff *skb, __be32 net_seq)
123 {
124         u32 diff;
125         u32 seq = ntohl(net_seq);
126 
127         if (!x->props.replay_window)
128                 return 0;
129 
130         if (unlikely(seq == 0))
131                 goto err;
132 
133         if (likely(seq > x->replay.seq))
134                 return 0;
135 
136         diff = x->replay.seq - seq;
137         if (diff >= x->props.replay_window) {
138                 x->stats.replay_window++;
139                 goto err;
140         }
141 
142         if (x->replay.bitmap & (1U << diff)) {
143                 x->stats.replay++;
144                 goto err;
145         }
146         return 0;
147 
148 err:
149         xfrm_audit_state_replay(x, skb, net_seq);
150         return -EINVAL;
151 }
152 
153 static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq);
154 static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq);
155 
156 void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
157 {
158         u32 diff, seq;
159 
160         switch (x->repl_mode) {
161         case XFRM_REPLAY_MODE_LEGACY:
162                 break;
163         case XFRM_REPLAY_MODE_BMP:
164                 return xfrm_replay_advance_bmp(x, net_seq);
165         case XFRM_REPLAY_MODE_ESN:
166                 return xfrm_replay_advance_esn(x, net_seq);
167         }
168 
169         if (!x->props.replay_window)
170                 return;
171 
172         seq = ntohl(net_seq);
173         if (seq > x->replay.seq) {
174                 diff = seq - x->replay.seq;
175                 if (diff < x->props.replay_window)
176                         x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
177                 else
178                         x->replay.bitmap = 1;
179                 x->replay.seq = seq;
180         } else {
181                 diff = x->replay.seq - seq;
182                 x->replay.bitmap |= (1U << diff);
183         }
184 
185         if (xfrm_aevent_is_on(xs_net(x)))
186                 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
187 }
188 
189 static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
190 {
191         int err = 0;
192         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
193         struct net *net = xs_net(x);
194 
195         if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
196                 XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
197                 XFRM_SKB_CB(skb)->seq.output.hi = 0;
198                 if (unlikely(replay_esn->oseq == 0) &&
199                     !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
200                         replay_esn->oseq--;
201                         xfrm_audit_state_replay_overflow(x, skb);
202                         err = -EOVERFLOW;
203 
204                         return err;
205                 }
206                 if (xfrm_aevent_is_on(net))
207                         xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
208         }
209 
210         return err;
211 }
212 
213 static int xfrm_replay_check_bmp(struct xfrm_state *x,
214                                  struct sk_buff *skb, __be32 net_seq)
215 {
216         unsigned int bitnr, nr;
217         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
218         u32 pos;
219         u32 seq = ntohl(net_seq);
220         u32 diff =  replay_esn->seq - seq;
221 
222         if (!replay_esn->replay_window)
223                 return 0;
224 
225         if (unlikely(seq == 0))
226                 goto err;
227 
228         if (likely(seq > replay_esn->seq))
229                 return 0;
230 
231         if (diff >= replay_esn->replay_window) {
232                 x->stats.replay_window++;
233                 goto err;
234         }
235 
236         pos = (replay_esn->seq - 1) % replay_esn->replay_window;
237 
238         if (pos >= diff)
239                 bitnr = (pos - diff) % replay_esn->replay_window;
240         else
241                 bitnr = replay_esn->replay_window - (diff - pos);
242 
243         nr = bitnr >> 5;
244         bitnr = bitnr & 0x1F;
245         if (replay_esn->bmp[nr] & (1U << bitnr))
246                 goto err_replay;
247 
248         return 0;
249 
250 err_replay:
251         x->stats.replay++;
252 err:
253         xfrm_audit_state_replay(x, skb, net_seq);
254         return -EINVAL;
255 }
256 
257 static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
258 {
259         unsigned int bitnr, nr, i;
260         u32 diff;
261         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
262         u32 seq = ntohl(net_seq);
263         u32 pos;
264 
265         if (!replay_esn->replay_window)
266                 return;
267 
268         pos = (replay_esn->seq - 1) % replay_esn->replay_window;
269 
270         if (seq > replay_esn->seq) {
271                 diff = seq - replay_esn->seq;
272 
273                 if (diff < replay_esn->replay_window) {
274                         for (i = 1; i < diff; i++) {
275                                 bitnr = (pos + i) % replay_esn->replay_window;
276                                 nr = bitnr >> 5;
277                                 bitnr = bitnr & 0x1F;
278                                 replay_esn->bmp[nr] &=  ~(1U << bitnr);
279                         }
280                 } else {
281                         nr = (replay_esn->replay_window - 1) >> 5;
282                         for (i = 0; i <= nr; i++)
283                                 replay_esn->bmp[i] = 0;
284                 }
285 
286                 bitnr = (pos + diff) % replay_esn->replay_window;
287                 replay_esn->seq = seq;
288         } else {
289                 diff = replay_esn->seq - seq;
290 
291                 if (pos >= diff)
292                         bitnr = (pos - diff) % replay_esn->replay_window;
293                 else
294                         bitnr = replay_esn->replay_window - (diff - pos);
295         }
296 
297         nr = bitnr >> 5;
298         bitnr = bitnr & 0x1F;
299         replay_esn->bmp[nr] |= (1U << bitnr);
300 
301         if (xfrm_aevent_is_on(xs_net(x)))
302                 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
303 }
304 
305 static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
306 {
307         struct km_event c;
308         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
309         struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
310 
311         /* we send notify messages in case
312          *  1. we updated on of the sequence numbers, and the seqno difference
313          *     is at least x->replay_maxdiff, in this case we also update the
314          *     timeout of our timer function
315          *  2. if x->replay_maxage has elapsed since last update,
316          *     and there were changes
317          *
318          *  The state structure must be locked!
319          */
320 
321         switch (event) {
322         case XFRM_REPLAY_UPDATE:
323                 if (!x->replay_maxdiff ||
324                     ((replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
325                     (replay_esn->oseq - preplay_esn->oseq
326                      < x->replay_maxdiff))) {
327                         if (x->xflags & XFRM_TIME_DEFER)
328                                 event = XFRM_REPLAY_TIMEOUT;
329                         else
330                                 return;
331                 }
332 
333                 break;
334 
335         case XFRM_REPLAY_TIMEOUT:
336                 if (memcmp(x->replay_esn, x->preplay_esn,
337                            xfrm_replay_state_esn_len(replay_esn)) == 0) {
338                         x->xflags |= XFRM_TIME_DEFER;
339                         return;
340                 }
341 
342                 break;
343         }
344 
345         memcpy(x->preplay_esn, x->replay_esn,
346                xfrm_replay_state_esn_len(replay_esn));
347         c.event = XFRM_MSG_NEWAE;
348         c.data.aevent = event;
349         km_state_notify(x, &c);
350 
351         if (x->replay_maxage &&
352             !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
353                 x->xflags &= ~XFRM_TIME_DEFER;
354 }
355 
356 static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
357 {
358         u32 seq_diff, oseq_diff;
359         struct km_event c;
360         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
361         struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
362 
363         /* we send notify messages in case
364          *  1. we updated on of the sequence numbers, and the seqno difference
365          *     is at least x->replay_maxdiff, in this case we also update the
366          *     timeout of our timer function
367          *  2. if x->replay_maxage has elapsed since last update,
368          *     and there were changes
369          *
370          *  The state structure must be locked!
371          */
372 
373         switch (event) {
374         case XFRM_REPLAY_UPDATE:
375                 if (x->replay_maxdiff) {
376                         if (replay_esn->seq_hi == preplay_esn->seq_hi)
377                                 seq_diff = replay_esn->seq - preplay_esn->seq;
378                         else
379                                 seq_diff = ~preplay_esn->seq + replay_esn->seq
380                                            + 1;
381 
382                         if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
383                                 oseq_diff = replay_esn->oseq
384                                             - preplay_esn->oseq;
385                         else
386                                 oseq_diff = ~preplay_esn->oseq
387                                             + replay_esn->oseq + 1;
388 
389                         if (seq_diff >= x->replay_maxdiff ||
390                             oseq_diff >= x->replay_maxdiff)
391                                 break;
392                 }
393 
394                 if (x->xflags & XFRM_TIME_DEFER)
395                         event = XFRM_REPLAY_TIMEOUT;
396                 else
397                         return;
398 
399                 break;
400 
401         case XFRM_REPLAY_TIMEOUT:
402                 if (memcmp(x->replay_esn, x->preplay_esn,
403                            xfrm_replay_state_esn_len(replay_esn)) == 0) {
404                         x->xflags |= XFRM_TIME_DEFER;
405                         return;
406                 }
407 
408                 break;
409         }
410 
411         memcpy(x->preplay_esn, x->replay_esn,
412                xfrm_replay_state_esn_len(replay_esn));
413         c.event = XFRM_MSG_NEWAE;
414         c.data.aevent = event;
415         km_state_notify(x, &c);
416 
417         if (x->replay_maxage &&
418             !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
419                 x->xflags &= ~XFRM_TIME_DEFER;
420 }
421 
422 static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
423 {
424         int err = 0;
425         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
426         struct net *net = xs_net(x);
427 
428         if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
429                 XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
430                 XFRM_SKB_CB(skb)->seq.output.hi = replay_esn->oseq_hi;
431 
432                 if (unlikely(replay_esn->oseq == 0)) {
433                         XFRM_SKB_CB(skb)->seq.output.hi = ++replay_esn->oseq_hi;
434 
435                         if (replay_esn->oseq_hi == 0) {
436                                 replay_esn->oseq--;
437                                 replay_esn->oseq_hi--;
438                                 xfrm_audit_state_replay_overflow(x, skb);
439                                 err = -EOVERFLOW;
440 
441                                 return err;
442                         }
443                 }
444                 if (xfrm_aevent_is_on(net))
445                         xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
446         }
447 
448         return err;
449 }
450 
451 static int xfrm_replay_check_esn(struct xfrm_state *x,
452                                  struct sk_buff *skb, __be32 net_seq)
453 {
454         unsigned int bitnr, nr;
455         u32 diff;
456         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
457         u32 pos;
458         u32 seq = ntohl(net_seq);
459         u32 wsize = replay_esn->replay_window;
460         u32 top = replay_esn->seq;
461         u32 bottom = top - wsize + 1;
462 
463         if (!wsize)
464                 return 0;
465 
466         if (unlikely(seq == 0 && replay_esn->seq_hi == 0 &&
467                      (replay_esn->seq < replay_esn->replay_window - 1)))
468                 goto err;
469 
470         diff = top - seq;
471 
472         if (likely(top >= wsize - 1)) {
473                 /* A. same subspace */
474                 if (likely(seq > top) || seq < bottom)
475                         return 0;
476         } else {
477                 /* B. window spans two subspaces */
478                 if (likely(seq > top && seq < bottom))
479                         return 0;
480                 if (seq >= bottom)
481                         diff = ~seq + top + 1;
482         }
483 
484         if (diff >= replay_esn->replay_window) {
485                 x->stats.replay_window++;
486                 goto err;
487         }
488 
489         pos = (replay_esn->seq - 1) % replay_esn->replay_window;
490 
491         if (pos >= diff)
492                 bitnr = (pos - diff) % replay_esn->replay_window;
493         else
494                 bitnr = replay_esn->replay_window - (diff - pos);
495 
496         nr = bitnr >> 5;
497         bitnr = bitnr & 0x1F;
498         if (replay_esn->bmp[nr] & (1U << bitnr))
499                 goto err_replay;
500 
501         return 0;
502 
503 err_replay:
504         x->stats.replay++;
505 err:
506         xfrm_audit_state_replay(x, skb, net_seq);
507         return -EINVAL;
508 }
509 
510 int xfrm_replay_check(struct xfrm_state *x,
511                       struct sk_buff *skb, __be32 net_seq)
512 {
513         switch (x->repl_mode) {
514         case XFRM_REPLAY_MODE_LEGACY:
515                 break;
516         case XFRM_REPLAY_MODE_BMP:
517                 return xfrm_replay_check_bmp(x, skb, net_seq);
518         case XFRM_REPLAY_MODE_ESN:
519                 return xfrm_replay_check_esn(x, skb, net_seq);
520         }
521 
522         return xfrm_replay_check_legacy(x, skb, net_seq);
523 }
524 
525 static int xfrm_replay_recheck_esn(struct xfrm_state *x,
526                                    struct sk_buff *skb, __be32 net_seq)
527 {
528         if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi !=
529                      htonl(xfrm_replay_seqhi(x, net_seq)))) {
530                         x->stats.replay_window++;
531                         return -EINVAL;
532         }
533 
534         return xfrm_replay_check_esn(x, skb, net_seq);
535 }
536 
537 int xfrm_replay_recheck(struct xfrm_state *x,
538                         struct sk_buff *skb, __be32 net_seq)
539 {
540         switch (x->repl_mode) {
541         case XFRM_REPLAY_MODE_LEGACY:
542                 break;
543         case XFRM_REPLAY_MODE_BMP:
544                 /* no special recheck treatment */
545                 return xfrm_replay_check_bmp(x, skb, net_seq);
546         case XFRM_REPLAY_MODE_ESN:
547                 return xfrm_replay_recheck_esn(x, skb, net_seq);
548         }
549 
550         return xfrm_replay_check_legacy(x, skb, net_seq);
551 }
552 
553 static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
554 {
555         unsigned int bitnr, nr, i;
556         int wrap;
557         u32 diff, pos, seq, seq_hi;
558         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
559 
560         if (!replay_esn->replay_window)
561                 return;
562 
563         seq = ntohl(net_seq);
564         pos = (replay_esn->seq - 1) % replay_esn->replay_window;
565         seq_hi = xfrm_replay_seqhi(x, net_seq);
566         wrap = seq_hi - replay_esn->seq_hi;
567 
568         if ((!wrap && seq > replay_esn->seq) || wrap > 0) {
569                 if (likely(!wrap))
570                         diff = seq - replay_esn->seq;
571                 else
572                         diff = ~replay_esn->seq + seq + 1;
573 
574                 if (diff < replay_esn->replay_window) {
575                         for (i = 1; i < diff; i++) {
576                                 bitnr = (pos + i) % replay_esn->replay_window;
577                                 nr = bitnr >> 5;
578                                 bitnr = bitnr & 0x1F;
579                                 replay_esn->bmp[nr] &=  ~(1U << bitnr);
580                         }
581                 } else {
582                         nr = (replay_esn->replay_window - 1) >> 5;
583                         for (i = 0; i <= nr; i++)
584                                 replay_esn->bmp[i] = 0;
585                 }
586 
587                 bitnr = (pos + diff) % replay_esn->replay_window;
588                 replay_esn->seq = seq;
589 
590                 if (unlikely(wrap > 0))
591                         replay_esn->seq_hi++;
592         } else {
593                 diff = replay_esn->seq - seq;
594 
595                 if (pos >= diff)
596                         bitnr = (pos - diff) % replay_esn->replay_window;
597                 else
598                         bitnr = replay_esn->replay_window - (diff - pos);
599         }
600 
601         xfrm_dev_state_advance_esn(x);
602 
603         nr = bitnr >> 5;
604         bitnr = bitnr & 0x1F;
605         replay_esn->bmp[nr] |= (1U << bitnr);
606 
607         if (xfrm_aevent_is_on(xs_net(x)))
608                 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
609 }
610 
611 #ifdef CONFIG_XFRM_OFFLOAD
612 static int xfrm_replay_overflow_offload(struct xfrm_state *x, struct sk_buff *skb)
613 {
614         int err = 0;
615         struct net *net = xs_net(x);
616         struct xfrm_offload *xo = xfrm_offload(skb);
617         __u32 oseq = x->replay.oseq;
618 
619         if (!xo)
620                 return __xfrm_replay_overflow(x, skb);
621 
622         if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
623                 if (!skb_is_gso(skb)) {
624                         XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
625                         xo->seq.low = oseq;
626                 } else {
627                         XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
628                         xo->seq.low = oseq + 1;
629                         oseq += skb_shinfo(skb)->gso_segs;
630                 }
631 
632                 XFRM_SKB_CB(skb)->seq.output.hi = 0;
633                 xo->seq.hi = 0;
634                 if (unlikely(oseq < x->replay.oseq) &&
635                     !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
636                         xfrm_audit_state_replay_overflow(x, skb);
637                         err = -EOVERFLOW;
638 
639                         return err;
640                 }
641 
642                 x->replay.oseq = oseq;
643 
644                 if (xfrm_aevent_is_on(net))
645                         xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
646         }
647 
648         return err;
649 }
650 
651 static int xfrm_replay_overflow_offload_bmp(struct xfrm_state *x, struct sk_buff *skb)
652 {
653         int err = 0;
654         struct xfrm_offload *xo = xfrm_offload(skb);
655         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
656         struct net *net = xs_net(x);
657         __u32 oseq = replay_esn->oseq;
658 
659         if (!xo)
660                 return xfrm_replay_overflow_bmp(x, skb);
661 
662         if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
663                 if (!skb_is_gso(skb)) {
664                         XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
665                         xo->seq.low = oseq;
666                 } else {
667                         XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
668                         xo->seq.low = oseq + 1;
669                         oseq += skb_shinfo(skb)->gso_segs;
670                 }
671 
672                 XFRM_SKB_CB(skb)->seq.output.hi = 0;
673                 xo->seq.hi = 0;
674                 if (unlikely(oseq < replay_esn->oseq) &&
675                     !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
676                         xfrm_audit_state_replay_overflow(x, skb);
677                         err = -EOVERFLOW;
678 
679                         return err;
680                 } else {
681                         replay_esn->oseq = oseq;
682                 }
683 
684                 if (xfrm_aevent_is_on(net))
685                         xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
686         }
687 
688         return err;
689 }
690 
691 static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff *skb)
692 {
693         int err = 0;
694         struct xfrm_offload *xo = xfrm_offload(skb);
695         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
696         struct net *net = xs_net(x);
697         __u32 oseq = replay_esn->oseq;
698         __u32 oseq_hi = replay_esn->oseq_hi;
699 
700         if (!xo)
701                 return xfrm_replay_overflow_esn(x, skb);
702 
703         if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
704                 if (!skb_is_gso(skb)) {
705                         XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
706                         XFRM_SKB_CB(skb)->seq.output.hi = oseq_hi;
707                         xo->seq.low = oseq;
708                         xo->seq.hi = oseq_hi;
709                 } else {
710                         XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
711                         XFRM_SKB_CB(skb)->seq.output.hi = oseq_hi;
712                         xo->seq.low = oseq + 1;
713                         xo->seq.hi = oseq_hi;
714                         oseq += skb_shinfo(skb)->gso_segs;
715                 }
716 
717                 if (unlikely(xo->seq.low < replay_esn->oseq)) {
718                         XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi;
719                         xo->seq.hi = oseq_hi;
720                         replay_esn->oseq_hi = oseq_hi;
721                         if (replay_esn->oseq_hi == 0) {
722                                 replay_esn->oseq--;
723                                 replay_esn->oseq_hi--;
724                                 xfrm_audit_state_replay_overflow(x, skb);
725                                 err = -EOVERFLOW;
726 
727                                 return err;
728                         }
729                 }
730 
731                 replay_esn->oseq = oseq;
732 
733                 if (xfrm_aevent_is_on(net))
734                         xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
735         }
736 
737         return err;
738 }
739 
740 int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
741 {
742         switch (x->repl_mode) {
743         case XFRM_REPLAY_MODE_LEGACY:
744                 break;
745         case XFRM_REPLAY_MODE_BMP:
746                 return xfrm_replay_overflow_offload_bmp(x, skb);
747         case XFRM_REPLAY_MODE_ESN:
748                 return xfrm_replay_overflow_offload_esn(x, skb);
749         }
750 
751         return xfrm_replay_overflow_offload(x, skb);
752 }
753 #else
754 int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
755 {
756         switch (x->repl_mode) {
757         case XFRM_REPLAY_MODE_LEGACY:
758                 break;
759         case XFRM_REPLAY_MODE_BMP:
760                 return xfrm_replay_overflow_bmp(x, skb);
761         case XFRM_REPLAY_MODE_ESN:
762                 return xfrm_replay_overflow_esn(x, skb);
763         }
764 
765         return __xfrm_replay_overflow(x, skb);
766 }
767 #endif
768 
769 int xfrm_init_replay(struct xfrm_state *x, struct netlink_ext_ack *extack)
770 {
771         struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
772 
773         if (replay_esn) {
774                 if (replay_esn->replay_window >
775                     replay_esn->bmp_len * sizeof(__u32) * 8) {
776                         NL_SET_ERR_MSG(extack, "ESN replay window is too large for the chosen bitmap size");
777                         return -EINVAL;
778                 }
779 
780                 if (x->props.flags & XFRM_STATE_ESN) {
781                         if (replay_esn->replay_window == 0 &&
782                             (!x->dir || x->dir == XFRM_SA_DIR_IN)) {
783                                 NL_SET_ERR_MSG(extack, "ESN replay window must be > 0");
784                                 return -EINVAL;
785                         }
786                         x->repl_mode = XFRM_REPLAY_MODE_ESN;
787                 } else {
788                         x->repl_mode = XFRM_REPLAY_MODE_BMP;
789                 }
790         } else {
791                 x->repl_mode = XFRM_REPLAY_MODE_LEGACY;
792         }
793 
794         return 0;
795 }
796 EXPORT_SYMBOL(xfrm_init_replay);
797 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php