Branch data Line data Source code
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 : 0 : u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq)
13 : : {
14 : 0 : u32 seq, seq_hi, bottom;
15 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
16 : :
17 [ # # ]: 0 : if (!(x->props.flags & XFRM_STATE_ESN))
18 : : return 0;
19 : :
20 : 0 : seq = ntohl(net_seq);
21 : 0 : seq_hi = replay_esn->seq_hi;
22 : 0 : bottom = replay_esn->seq - replay_esn->replay_window + 1;
23 : :
24 [ # # # # : 0 : if (likely(replay_esn->seq >= replay_esn->replay_window - 1)) {
# # ]
25 : : /* A. same subspace */
26 [ # # # # : 0 : if (unlikely(seq < bottom))
# # ]
27 : 0 : seq_hi++;
28 : : } else {
29 : : /* B. window spans two subspaces */
30 [ # # # # : 0 : if (unlikely(seq >= bottom))
# # ]
31 : 0 : seq_hi--;
32 : : }
33 : :
34 : : return seq_hi;
35 : : }
36 : : EXPORT_SYMBOL(xfrm_replay_seqhi);
37 : : ;
38 : 0 : static void xfrm_replay_notify(struct xfrm_state *x, int event)
39 : : {
40 : 0 : struct km_event c;
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
47 : : *
48 : : * The state structure must be locked!
49 : : */
50 : :
51 [ # # # ]: 0 : switch (event) {
52 : 0 : case XFRM_REPLAY_UPDATE:
53 [ # # ]: 0 : if (!x->replay_maxdiff ||
54 [ # # ]: 0 : ((x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
55 [ # # ]: 0 : (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))) {
56 [ # # ]: 0 : if (x->xflags & XFRM_TIME_DEFER)
57 : : event = XFRM_REPLAY_TIMEOUT;
58 : : else
59 : 0 : return;
60 : : }
61 : :
62 : : break;
63 : :
64 : 0 : case XFRM_REPLAY_TIMEOUT:
65 [ # # ]: 0 : if (memcmp(&x->replay, &x->preplay,
66 : : sizeof(struct xfrm_replay_state)) == 0) {
67 : 0 : x->xflags |= XFRM_TIME_DEFER;
68 : 0 : return;
69 : : }
70 : :
71 : : break;
72 : : }
73 : :
74 : 0 : memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
75 : 0 : c.event = XFRM_MSG_NEWAE;
76 : 0 : c.data.aevent = event;
77 : 0 : km_state_notify(x, &c);
78 : :
79 [ # # # # ]: 0 : if (x->replay_maxage &&
80 : 0 : !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
81 : 0 : x->xflags &= ~XFRM_TIME_DEFER;
82 : : }
83 : :
84 : 0 : static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
85 : : {
86 : 0 : int err = 0;
87 [ # # ]: 0 : struct net *net = xs_net(x);
88 : :
89 [ # # ]: 0 : if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
90 : 0 : XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq;
91 : 0 : XFRM_SKB_CB(skb)->seq.output.hi = 0;
92 [ # # ]: 0 : if (unlikely(x->replay.oseq == 0)) {
93 : 0 : x->replay.oseq--;
94 : 0 : xfrm_audit_state_replay_overflow(x, skb);
95 : 0 : err = -EOVERFLOW;
96 : :
97 : 0 : return err;
98 : : }
99 [ # # ]: 0 : if (xfrm_aevent_is_on(net))
100 : 0 : x->repl->notify(x, XFRM_REPLAY_UPDATE);
101 : : }
102 : :
103 : : return err;
104 : : }
105 : :
106 : 0 : static int xfrm_replay_check(struct xfrm_state *x,
107 : : struct sk_buff *skb, __be32 net_seq)
108 : : {
109 : 0 : u32 diff;
110 : 0 : u32 seq = ntohl(net_seq);
111 : :
112 [ # # ]: 0 : if (!x->props.replay_window)
113 : : return 0;
114 : :
115 [ # # ]: 0 : if (unlikely(seq == 0))
116 : 0 : goto err;
117 : :
118 [ # # ]: 0 : if (likely(seq > x->replay.seq))
119 : : return 0;
120 : :
121 : 0 : diff = x->replay.seq - seq;
122 [ # # ]: 0 : if (diff >= x->props.replay_window) {
123 : 0 : x->stats.replay_window++;
124 : 0 : goto err;
125 : : }
126 : :
127 [ # # ]: 0 : if (x->replay.bitmap & (1U << diff)) {
128 : 0 : x->stats.replay++;
129 : 0 : goto err;
130 : : }
131 : : return 0;
132 : :
133 : 0 : err:
134 : 0 : xfrm_audit_state_replay(x, skb, net_seq);
135 : 0 : return -EINVAL;
136 : : }
137 : :
138 : 0 : static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
139 : : {
140 : 0 : u32 diff;
141 : 0 : u32 seq = ntohl(net_seq);
142 : :
143 [ # # ]: 0 : if (!x->props.replay_window)
144 : : return;
145 : :
146 [ # # ]: 0 : if (seq > x->replay.seq) {
147 : 0 : diff = seq - x->replay.seq;
148 [ # # ]: 0 : if (diff < x->props.replay_window)
149 : 0 : x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
150 : : else
151 : 0 : x->replay.bitmap = 1;
152 : 0 : x->replay.seq = seq;
153 : : } else {
154 : 0 : diff = x->replay.seq - seq;
155 : 0 : x->replay.bitmap |= (1U << diff);
156 : : }
157 : :
158 [ # # ]: 0 : if (xfrm_aevent_is_on(xs_net(x)))
159 : 0 : x->repl->notify(x, XFRM_REPLAY_UPDATE);
160 : : }
161 : :
162 : 0 : static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
163 : : {
164 : 0 : int err = 0;
165 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
166 [ # # ]: 0 : struct net *net = xs_net(x);
167 : :
168 [ # # ]: 0 : if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
169 : 0 : XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
170 : 0 : XFRM_SKB_CB(skb)->seq.output.hi = 0;
171 [ # # ]: 0 : if (unlikely(replay_esn->oseq == 0)) {
172 : 0 : replay_esn->oseq--;
173 : 0 : xfrm_audit_state_replay_overflow(x, skb);
174 : 0 : err = -EOVERFLOW;
175 : :
176 : 0 : return err;
177 : : }
178 [ # # ]: 0 : if (xfrm_aevent_is_on(net))
179 : 0 : x->repl->notify(x, XFRM_REPLAY_UPDATE);
180 : : }
181 : :
182 : : return err;
183 : : }
184 : :
185 : 0 : static int xfrm_replay_check_bmp(struct xfrm_state *x,
186 : : struct sk_buff *skb, __be32 net_seq)
187 : : {
188 : 0 : unsigned int bitnr, nr;
189 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
190 : 0 : u32 pos;
191 : 0 : u32 seq = ntohl(net_seq);
192 : 0 : u32 diff = replay_esn->seq - seq;
193 : :
194 [ # # ]: 0 : if (!replay_esn->replay_window)
195 : : return 0;
196 : :
197 [ # # ]: 0 : if (unlikely(seq == 0))
198 : 0 : goto err;
199 : :
200 [ # # ]: 0 : if (likely(seq > replay_esn->seq))
201 : : return 0;
202 : :
203 [ # # ]: 0 : if (diff >= replay_esn->replay_window) {
204 : 0 : x->stats.replay_window++;
205 : 0 : goto err;
206 : : }
207 : :
208 : 0 : pos = (replay_esn->seq - 1) % replay_esn->replay_window;
209 : :
210 [ # # ]: 0 : if (pos >= diff)
211 : 0 : bitnr = (pos - diff) % replay_esn->replay_window;
212 : : else
213 : 0 : bitnr = replay_esn->replay_window - (diff - pos);
214 : :
215 : 0 : nr = bitnr >> 5;
216 : 0 : bitnr = bitnr & 0x1F;
217 [ # # ]: 0 : if (replay_esn->bmp[nr] & (1U << bitnr))
218 : 0 : goto err_replay;
219 : :
220 : : return 0;
221 : :
222 : : err_replay:
223 : 0 : x->stats.replay++;
224 : 0 : err:
225 : 0 : xfrm_audit_state_replay(x, skb, net_seq);
226 : 0 : return -EINVAL;
227 : : }
228 : :
229 : 0 : static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
230 : : {
231 : 0 : unsigned int bitnr, nr, i;
232 : 0 : u32 diff;
233 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
234 : 0 : u32 seq = ntohl(net_seq);
235 : 0 : u32 pos;
236 : :
237 [ # # ]: 0 : if (!replay_esn->replay_window)
238 : : return;
239 : :
240 : 0 : pos = (replay_esn->seq - 1) % replay_esn->replay_window;
241 : :
242 [ # # ]: 0 : if (seq > replay_esn->seq) {
243 : 0 : diff = seq - replay_esn->seq;
244 : :
245 [ # # ]: 0 : if (diff < replay_esn->replay_window) {
246 [ # # ]: 0 : for (i = 1; i < diff; i++) {
247 : 0 : bitnr = (pos + i) % replay_esn->replay_window;
248 : 0 : nr = bitnr >> 5;
249 : 0 : bitnr = bitnr & 0x1F;
250 : 0 : replay_esn->bmp[nr] &= ~(1U << bitnr);
251 : : }
252 : : } else {
253 : 0 : nr = (replay_esn->replay_window - 1) >> 5;
254 [ # # ]: 0 : for (i = 0; i <= nr; i++)
255 : 0 : replay_esn->bmp[i] = 0;
256 : : }
257 : :
258 : 0 : bitnr = (pos + diff) % replay_esn->replay_window;
259 : 0 : replay_esn->seq = seq;
260 : : } else {
261 : 0 : diff = replay_esn->seq - seq;
262 : :
263 [ # # ]: 0 : if (pos >= diff)
264 : 0 : bitnr = (pos - diff) % replay_esn->replay_window;
265 : : else
266 : 0 : bitnr = replay_esn->replay_window - (diff - pos);
267 : : }
268 : :
269 : 0 : nr = bitnr >> 5;
270 : 0 : bitnr = bitnr & 0x1F;
271 : 0 : replay_esn->bmp[nr] |= (1U << bitnr);
272 : :
273 [ # # ]: 0 : if (xfrm_aevent_is_on(xs_net(x)))
274 : 0 : x->repl->notify(x, XFRM_REPLAY_UPDATE);
275 : : }
276 : :
277 : 0 : static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
278 : : {
279 : 0 : struct km_event c;
280 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
281 : 0 : struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
282 : :
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
289 : : *
290 : : * The state structure must be locked!
291 : : */
292 : :
293 [ # # # ]: 0 : switch (event) {
294 : 0 : case XFRM_REPLAY_UPDATE:
295 [ # # ]: 0 : if (!x->replay_maxdiff ||
296 [ # # ]: 0 : ((replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
297 [ # # ]: 0 : (replay_esn->oseq - preplay_esn->oseq
298 : : < x->replay_maxdiff))) {
299 [ # # ]: 0 : if (x->xflags & XFRM_TIME_DEFER)
300 : : event = XFRM_REPLAY_TIMEOUT;
301 : : else
302 : 0 : return;
303 : : }
304 : :
305 : : break;
306 : :
307 : 0 : case XFRM_REPLAY_TIMEOUT:
308 : 0 : if (memcmp(x->replay_esn, x->preplay_esn,
309 [ # # ]: 0 : xfrm_replay_state_esn_len(replay_esn)) == 0) {
310 : 0 : x->xflags |= XFRM_TIME_DEFER;
311 : 0 : return;
312 : : }
313 : :
314 : : break;
315 : : }
316 : :
317 : 0 : memcpy(x->preplay_esn, x->replay_esn,
318 : 0 : xfrm_replay_state_esn_len(replay_esn));
319 : 0 : c.event = XFRM_MSG_NEWAE;
320 : 0 : c.data.aevent = event;
321 : 0 : km_state_notify(x, &c);
322 : :
323 [ # # # # ]: 0 : if (x->replay_maxage &&
324 : 0 : !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
325 : 0 : x->xflags &= ~XFRM_TIME_DEFER;
326 : : }
327 : :
328 : 0 : static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
329 : : {
330 : 0 : u32 seq_diff, oseq_diff;
331 : 0 : struct km_event c;
332 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
333 : 0 : struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
334 : :
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
341 : : *
342 : : * The state structure must be locked!
343 : : */
344 : :
345 [ # # # ]: 0 : switch (event) {
346 : 0 : case XFRM_REPLAY_UPDATE:
347 [ # # ]: 0 : if (x->replay_maxdiff) {
348 [ # # ]: 0 : if (replay_esn->seq_hi == preplay_esn->seq_hi)
349 : 0 : seq_diff = replay_esn->seq - preplay_esn->seq;
350 : : else
351 : 0 : seq_diff = ~preplay_esn->seq + replay_esn->seq
352 : : + 1;
353 : :
354 [ # # ]: 0 : if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
355 : 0 : oseq_diff = replay_esn->oseq
356 : 0 : - preplay_esn->oseq;
357 : : else
358 : 0 : oseq_diff = ~preplay_esn->oseq
359 : 0 : + replay_esn->oseq + 1;
360 : :
361 [ # # # # ]: 0 : if (seq_diff >= x->replay_maxdiff ||
362 : : oseq_diff >= x->replay_maxdiff)
363 : : break;
364 : : }
365 : :
366 [ # # ]: 0 : if (x->xflags & XFRM_TIME_DEFER)
367 : : event = XFRM_REPLAY_TIMEOUT;
368 : : else
369 : 0 : return;
370 : :
371 : : break;
372 : :
373 : 0 : case XFRM_REPLAY_TIMEOUT:
374 : 0 : if (memcmp(x->replay_esn, x->preplay_esn,
375 [ # # ]: 0 : xfrm_replay_state_esn_len(replay_esn)) == 0) {
376 : 0 : x->xflags |= XFRM_TIME_DEFER;
377 : 0 : return;
378 : : }
379 : :
380 : : break;
381 : : }
382 : :
383 : 0 : memcpy(x->preplay_esn, x->replay_esn,
384 : 0 : xfrm_replay_state_esn_len(replay_esn));
385 : 0 : c.event = XFRM_MSG_NEWAE;
386 : 0 : c.data.aevent = event;
387 : 0 : km_state_notify(x, &c);
388 : :
389 [ # # # # ]: 0 : if (x->replay_maxage &&
390 : 0 : !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
391 : 0 : x->xflags &= ~XFRM_TIME_DEFER;
392 : : }
393 : :
394 : 0 : static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
395 : : {
396 : 0 : int err = 0;
397 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
398 [ # # ]: 0 : struct net *net = xs_net(x);
399 : :
400 [ # # ]: 0 : if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
401 : 0 : XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
402 : 0 : XFRM_SKB_CB(skb)->seq.output.hi = replay_esn->oseq_hi;
403 : :
404 [ # # ]: 0 : if (unlikely(replay_esn->oseq == 0)) {
405 : 0 : XFRM_SKB_CB(skb)->seq.output.hi = ++replay_esn->oseq_hi;
406 : :
407 [ # # ]: 0 : if (replay_esn->oseq_hi == 0) {
408 : 0 : replay_esn->oseq--;
409 : 0 : replay_esn->oseq_hi--;
410 : 0 : xfrm_audit_state_replay_overflow(x, skb);
411 : 0 : err = -EOVERFLOW;
412 : :
413 : 0 : return err;
414 : : }
415 : : }
416 [ # # ]: 0 : if (xfrm_aevent_is_on(net))
417 : 0 : x->repl->notify(x, XFRM_REPLAY_UPDATE);
418 : : }
419 : :
420 : : return err;
421 : : }
422 : :
423 : 0 : static int xfrm_replay_check_esn(struct xfrm_state *x,
424 : : struct sk_buff *skb, __be32 net_seq)
425 : : {
426 : 0 : unsigned int bitnr, nr;
427 : 0 : u32 diff;
428 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
429 : 0 : u32 pos;
430 : 0 : u32 seq = ntohl(net_seq);
431 : 0 : u32 wsize = replay_esn->replay_window;
432 : 0 : u32 top = replay_esn->seq;
433 : 0 : u32 bottom = top - wsize + 1;
434 : :
435 [ # # ]: 0 : if (!wsize)
436 : : return 0;
437 : :
438 [ # # # # : 0 : if (unlikely(seq == 0 && replay_esn->seq_hi == 0 &&
# # ]
439 : : (replay_esn->seq < replay_esn->replay_window - 1)))
440 : 0 : goto err;
441 : :
442 : 0 : diff = top - seq;
443 : :
444 [ # # ]: 0 : if (likely(top >= wsize - 1)) {
445 : : /* A. same subspace */
446 [ # # # # ]: 0 : if (likely(seq > top) || seq < bottom)
447 : : return 0;
448 : : } else {
449 : : /* B. window spans two subspaces */
450 [ # # ]: 0 : if (likely(seq > top && seq < bottom))
451 : : return 0;
452 : : if (seq >= bottom)
453 : : diff = ~seq + top + 1;
454 : : }
455 : :
456 [ # # ]: 0 : if (diff >= replay_esn->replay_window) {
457 : 0 : x->stats.replay_window++;
458 : 0 : goto err;
459 : : }
460 : :
461 : 0 : pos = (replay_esn->seq - 1) % replay_esn->replay_window;
462 : :
463 [ # # ]: 0 : if (pos >= diff)
464 : 0 : bitnr = (pos - diff) % replay_esn->replay_window;
465 : : else
466 : 0 : bitnr = replay_esn->replay_window - (diff - pos);
467 : :
468 : 0 : nr = bitnr >> 5;
469 : 0 : bitnr = bitnr & 0x1F;
470 [ # # ]: 0 : if (replay_esn->bmp[nr] & (1U << bitnr))
471 : 0 : goto err_replay;
472 : :
473 : : return 0;
474 : :
475 : : err_replay:
476 : 0 : x->stats.replay++;
477 : 0 : err:
478 : 0 : xfrm_audit_state_replay(x, skb, net_seq);
479 : 0 : return -EINVAL;
480 : : }
481 : :
482 : 0 : static int xfrm_replay_recheck_esn(struct xfrm_state *x,
483 : : struct sk_buff *skb, __be32 net_seq)
484 : : {
485 [ # # # # ]: 0 : if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi !=
486 : : htonl(xfrm_replay_seqhi(x, net_seq)))) {
487 : 0 : x->stats.replay_window++;
488 : 0 : return -EINVAL;
489 : : }
490 : :
491 : 0 : return xfrm_replay_check_esn(x, skb, net_seq);
492 : : }
493 : :
494 : 0 : static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
495 : : {
496 : 0 : unsigned int bitnr, nr, i;
497 : 0 : int wrap;
498 : 0 : u32 diff, pos, seq, seq_hi;
499 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
500 : :
501 [ # # ]: 0 : if (!replay_esn->replay_window)
502 : : return;
503 : :
504 : 0 : seq = ntohl(net_seq);
505 : 0 : pos = (replay_esn->seq - 1) % replay_esn->replay_window;
506 [ # # ]: 0 : seq_hi = xfrm_replay_seqhi(x, net_seq);
507 : 0 : wrap = seq_hi - replay_esn->seq_hi;
508 : :
509 [ # # # # : 0 : if ((!wrap && seq > replay_esn->seq) || wrap > 0) {
# # ]
510 [ # # ]: 0 : if (likely(!wrap))
511 : 0 : diff = seq - replay_esn->seq;
512 : : else
513 : 0 : diff = ~replay_esn->seq + seq + 1;
514 : :
515 [ # # ]: 0 : if (diff < replay_esn->replay_window) {
516 [ # # ]: 0 : for (i = 1; i < diff; i++) {
517 : 0 : bitnr = (pos + i) % replay_esn->replay_window;
518 : 0 : nr = bitnr >> 5;
519 : 0 : bitnr = bitnr & 0x1F;
520 : 0 : replay_esn->bmp[nr] &= ~(1U << bitnr);
521 : : }
522 : : } else {
523 : 0 : nr = (replay_esn->replay_window - 1) >> 5;
524 [ # # ]: 0 : for (i = 0; i <= nr; i++)
525 : 0 : replay_esn->bmp[i] = 0;
526 : : }
527 : :
528 : 0 : bitnr = (pos + diff) % replay_esn->replay_window;
529 : 0 : replay_esn->seq = seq;
530 : :
531 [ # # ]: 0 : if (unlikely(wrap > 0))
532 : 0 : replay_esn->seq_hi++;
533 : : } else {
534 : 0 : diff = replay_esn->seq - seq;
535 : :
536 [ # # ]: 0 : if (pos >= diff)
537 : 0 : bitnr = (pos - diff) % replay_esn->replay_window;
538 : : else
539 : 0 : bitnr = replay_esn->replay_window - (diff - pos);
540 : : }
541 : :
542 : 0 : xfrm_dev_state_advance_esn(x);
543 : :
544 : 0 : nr = bitnr >> 5;
545 : 0 : bitnr = bitnr & 0x1F;
546 : 0 : replay_esn->bmp[nr] |= (1U << bitnr);
547 : :
548 [ # # ]: 0 : if (xfrm_aevent_is_on(xs_net(x)))
549 : 0 : x->repl->notify(x, XFRM_REPLAY_UPDATE);
550 : : }
551 : :
552 : : #ifdef CONFIG_XFRM_OFFLOAD
553 : : static int xfrm_replay_overflow_offload(struct xfrm_state *x, struct sk_buff *skb)
554 : : {
555 : : int err = 0;
556 : : struct net *net = xs_net(x);
557 : : struct xfrm_offload *xo = xfrm_offload(skb);
558 : : __u32 oseq = x->replay.oseq;
559 : :
560 : : if (!xo)
561 : : return xfrm_replay_overflow(x, skb);
562 : :
563 : : if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
564 : : if (!skb_is_gso(skb)) {
565 : : XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
566 : : xo->seq.low = oseq;
567 : : } else {
568 : : XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
569 : : xo->seq.low = oseq + 1;
570 : : oseq += skb_shinfo(skb)->gso_segs;
571 : : }
572 : :
573 : : XFRM_SKB_CB(skb)->seq.output.hi = 0;
574 : : xo->seq.hi = 0;
575 : : if (unlikely(oseq < x->replay.oseq)) {
576 : : xfrm_audit_state_replay_overflow(x, skb);
577 : : err = -EOVERFLOW;
578 : :
579 : : return err;
580 : : }
581 : :
582 : : x->replay.oseq = oseq;
583 : :
584 : : if (xfrm_aevent_is_on(net))
585 : : x->repl->notify(x, XFRM_REPLAY_UPDATE);
586 : : }
587 : :
588 : : return err;
589 : : }
590 : :
591 : : static int xfrm_replay_overflow_offload_bmp(struct xfrm_state *x, struct sk_buff *skb)
592 : : {
593 : : int err = 0;
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;
598 : :
599 : : if (!xo)
600 : : return xfrm_replay_overflow_bmp(x, skb);
601 : :
602 : : if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
603 : : if (!skb_is_gso(skb)) {
604 : : XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
605 : : xo->seq.low = oseq;
606 : : } else {
607 : : XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
608 : : xo->seq.low = oseq + 1;
609 : : oseq += skb_shinfo(skb)->gso_segs;
610 : : }
611 : :
612 : : XFRM_SKB_CB(skb)->seq.output.hi = 0;
613 : : xo->seq.hi = 0;
614 : : if (unlikely(oseq < replay_esn->oseq)) {
615 : : xfrm_audit_state_replay_overflow(x, skb);
616 : : err = -EOVERFLOW;
617 : :
618 : : return err;
619 : : } else {
620 : : replay_esn->oseq = oseq;
621 : : }
622 : :
623 : : if (xfrm_aevent_is_on(net))
624 : : x->repl->notify(x, XFRM_REPLAY_UPDATE);
625 : : }
626 : :
627 : : return err;
628 : : }
629 : :
630 : : static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff *skb)
631 : : {
632 : : int err = 0;
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;
638 : :
639 : : if (!xo)
640 : : return xfrm_replay_overflow_esn(x, skb);
641 : :
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;
646 : : xo->seq.low = oseq;
647 : : xo->seq.hi = oseq_hi;
648 : : } else {
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;
654 : : }
655 : :
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) {
661 : : replay_esn->oseq--;
662 : : replay_esn->oseq_hi--;
663 : : xfrm_audit_state_replay_overflow(x, skb);
664 : : err = -EOVERFLOW;
665 : :
666 : : return err;
667 : : }
668 : : }
669 : :
670 : : replay_esn->oseq = oseq;
671 : :
672 : : if (xfrm_aevent_is_on(net))
673 : : x->repl->notify(x, XFRM_REPLAY_UPDATE);
674 : : }
675 : :
676 : : return err;
677 : : }
678 : :
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,
685 : : };
686 : :
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,
693 : : };
694 : :
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,
701 : : };
702 : : #else
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,
709 : : };
710 : :
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,
717 : : };
718 : :
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,
725 : : };
726 : : #endif
727 : :
728 : 0 : int xfrm_init_replay(struct xfrm_state *x)
729 : : {
730 : 0 : struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
731 : :
732 [ # # ]: 0 : if (replay_esn) {
733 : 0 : if (replay_esn->replay_window >
734 [ # # ]: 0 : replay_esn->bmp_len * sizeof(__u32) * 8)
735 : : return -EINVAL;
736 : :
737 [ # # ]: 0 : if (x->props.flags & XFRM_STATE_ESN) {
738 [ # # ]: 0 : if (replay_esn->replay_window == 0)
739 : : return -EINVAL;
740 : 0 : x->repl = &xfrm_replay_esn;
741 : : } else {
742 : 0 : x->repl = &xfrm_replay_bmp;
743 : : }
744 : : } else {
745 : 0 : x->repl = &xfrm_replay_legacy;
746 : : }
747 : :
748 : : return 0;
749 : : }
750 : : EXPORT_SYMBOL(xfrm_init_replay);
|