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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.