Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: conntrack: avoid using ->error callback if possible

The error() handler gets called before allocating or looking up a
connection tracking entry.

We can instead use direct calls from the ->packet() handlers which get
invoked for every packet anyway.

Only exceptions are icmp and icmpv6, these two special cases will be
handled in the next patch.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
0150ffba 83d213fd

+91 -106
+45 -53
net/netfilter/nf_conntrack_proto_dccp.c
··· 435 435 ntohl(dhack->dccph_ack_nr_low); 436 436 } 437 437 438 + static bool dccp_error(const struct dccp_hdr *dh, 439 + struct sk_buff *skb, unsigned int dataoff, 440 + const struct nf_hook_state *state) 441 + { 442 + unsigned int dccp_len = skb->len - dataoff; 443 + unsigned int cscov; 444 + const char *msg; 445 + 446 + if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || 447 + dh->dccph_doff * 4 > dccp_len) { 448 + msg = "nf_ct_dccp: truncated/malformed packet "; 449 + goto out_invalid; 450 + } 451 + 452 + cscov = dccp_len; 453 + if (dh->dccph_cscov) { 454 + cscov = (dh->dccph_cscov - 1) * 4; 455 + if (cscov > dccp_len) { 456 + msg = "nf_ct_dccp: bad checksum coverage "; 457 + goto out_invalid; 458 + } 459 + } 460 + 461 + if (state->hook == NF_INET_PRE_ROUTING && 462 + state->net->ct.sysctl_checksum && 463 + nf_checksum_partial(skb, state->hook, dataoff, cscov, 464 + IPPROTO_DCCP, state->pf)) { 465 + msg = "nf_ct_dccp: bad checksum "; 466 + goto out_invalid; 467 + } 468 + 469 + if (dh->dccph_type >= DCCP_PKT_INVALID) { 470 + msg = "nf_ct_dccp: reserved packet type "; 471 + goto out_invalid; 472 + } 473 + return false; 474 + out_invalid: 475 + nf_l4proto_log_invalid(skb, state->net, state->pf, 476 + IPPROTO_DCCP, "%s", msg); 477 + return true; 478 + } 479 + 438 480 static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, 439 481 unsigned int dataoff, enum ip_conntrack_info ctinfo, 440 482 const struct nf_hook_state *state) ··· 490 448 dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); 491 449 if (!dh) 492 450 return NF_DROP; 451 + 452 + if (dccp_error(dh, skb, dataoff, state)) 453 + return -NF_ACCEPT; 493 454 494 455 type = dh->dccph_type; 495 456 if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh)) ··· 572 527 nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); 573 528 574 529 return NF_ACCEPT; 575 - } 576 - 577 - static int dccp_error(struct nf_conn *tmpl, 578 - struct sk_buff *skb, unsigned int dataoff, 579 - const struct nf_hook_state *state) 580 - { 581 - struct dccp_hdr _dh, *dh; 582 - unsigned int dccp_len = skb->len - dataoff; 583 - unsigned int cscov; 584 - const char *msg; 585 - 586 - dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); 587 - if (dh == NULL) { 588 - msg = "nf_ct_dccp: short packet "; 589 - goto out_invalid; 590 - } 591 - 592 - if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || 593 - dh->dccph_doff * 4 > dccp_len) { 594 - msg = "nf_ct_dccp: truncated/malformed packet "; 595 - goto out_invalid; 596 - } 597 - 598 - cscov = dccp_len; 599 - if (dh->dccph_cscov) { 600 - cscov = (dh->dccph_cscov - 1) * 4; 601 - if (cscov > dccp_len) { 602 - msg = "nf_ct_dccp: bad checksum coverage "; 603 - goto out_invalid; 604 - } 605 - } 606 - 607 - if (state->hook == NF_INET_PRE_ROUTING && 608 - state->net->ct.sysctl_checksum && 609 - nf_checksum_partial(skb, state->hook, dataoff, cscov, 610 - IPPROTO_DCCP, state->pf)) { 611 - msg = "nf_ct_dccp: bad checksum "; 612 - goto out_invalid; 613 - } 614 - 615 - if (dh->dccph_type >= DCCP_PKT_INVALID) { 616 - msg = "nf_ct_dccp: reserved packet type "; 617 - goto out_invalid; 618 - } 619 - 620 - return NF_ACCEPT; 621 - 622 - out_invalid: 623 - nf_l4proto_log_invalid(skb, state->net, state->pf, 624 - IPPROTO_DCCP, "%s", msg); 625 - return -NF_ACCEPT; 626 530 } 627 531 628 532 static bool dccp_can_early_drop(const struct nf_conn *ct) ··· 846 852 .l3proto = AF_INET, 847 853 .l4proto = IPPROTO_DCCP, 848 854 .packet = dccp_packet, 849 - .error = dccp_error, 850 855 .can_early_drop = dccp_can_early_drop, 851 856 #ifdef CONFIG_NF_CONNTRACK_PROCFS 852 857 .print_conntrack = dccp_print_conntrack, ··· 877 884 .l3proto = AF_INET6, 878 885 .l4proto = IPPROTO_DCCP, 879 886 .packet = dccp_packet, 880 - .error = dccp_error, 881 887 .can_early_drop = dccp_can_early_drop, 882 888 #ifdef CONFIG_NF_CONNTRACK_PROCFS 883 889 .print_conntrack = dccp_print_conntrack,
+34 -33
net/netfilter/nf_conntrack_proto_sctp.c
··· 330 330 return true; 331 331 } 332 332 333 + static bool sctp_error(struct sk_buff *skb, 334 + unsigned int dataoff, 335 + const struct nf_hook_state *state) 336 + { 337 + const struct sctphdr *sh; 338 + const char *logmsg; 339 + 340 + if (skb->len < dataoff + sizeof(struct sctphdr)) { 341 + logmsg = "nf_ct_sctp: short packet "; 342 + goto out_invalid; 343 + } 344 + if (state->hook == NF_INET_PRE_ROUTING && 345 + state->net->ct.sysctl_checksum && 346 + skb->ip_summed == CHECKSUM_NONE) { 347 + if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { 348 + logmsg = "nf_ct_sctp: failed to read header "; 349 + goto out_invalid; 350 + } 351 + sh = (const struct sctphdr *)(skb->data + dataoff); 352 + if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { 353 + logmsg = "nf_ct_sctp: bad CRC "; 354 + goto out_invalid; 355 + } 356 + skb->ip_summed = CHECKSUM_UNNECESSARY; 357 + } 358 + return false; 359 + out_invalid: 360 + nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); 361 + return true; 362 + } 363 + 333 364 /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ 334 365 static int sctp_packet(struct nf_conn *ct, 335 366 struct sk_buff *skb, ··· 377 346 u_int32_t offset, count; 378 347 unsigned int *timeouts; 379 348 unsigned long map[256 / sizeof(unsigned long)] = { 0 }; 349 + 350 + if (sctp_error(skb, dataoff, state)) 351 + return -NF_ACCEPT; 380 352 381 353 sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); 382 354 if (sh == NULL) ··· 497 463 out_unlock: 498 464 spin_unlock_bh(&ct->lock); 499 465 out: 500 - return -NF_ACCEPT; 501 - } 502 - 503 - static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb, 504 - unsigned int dataoff, 505 - const struct nf_hook_state *state) 506 - { 507 - const struct sctphdr *sh; 508 - const char *logmsg; 509 - 510 - if (skb->len < dataoff + sizeof(struct sctphdr)) { 511 - logmsg = "nf_ct_sctp: short packet "; 512 - goto out_invalid; 513 - } 514 - if (state->hook == NF_INET_PRE_ROUTING && 515 - state->net->ct.sysctl_checksum && 516 - skb->ip_summed == CHECKSUM_NONE) { 517 - if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { 518 - logmsg = "nf_ct_sctp: failed to read header "; 519 - goto out_invalid; 520 - } 521 - sh = (const struct sctphdr *)(skb->data + dataoff); 522 - if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { 523 - logmsg = "nf_ct_sctp: bad CRC "; 524 - goto out_invalid; 525 - } 526 - skb->ip_summed = CHECKSUM_UNNECESSARY; 527 - } 528 - return NF_ACCEPT; 529 - out_invalid: 530 - nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); 531 466 return -NF_ACCEPT; 532 467 } 533 468 ··· 766 763 .print_conntrack = sctp_print_conntrack, 767 764 #endif 768 765 .packet = sctp_packet, 769 - .error = sctp_error, 770 766 .can_early_drop = sctp_can_early_drop, 771 767 .me = THIS_MODULE, 772 768 #if IS_ENABLED(CONFIG_NF_CT_NETLINK) ··· 798 796 .print_conntrack = sctp_print_conntrack, 799 797 #endif 800 798 .packet = sctp_packet, 801 - .error = sctp_error, 802 799 .can_early_drop = sctp_can_early_drop, 803 800 .me = THIS_MODULE, 804 801 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
+12 -20
net/netfilter/nf_conntrack_proto_tcp.c
··· 725 725 } 726 726 727 727 /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ 728 - static int tcp_error(struct nf_conn *tmpl, 729 - struct sk_buff *skb, 730 - unsigned int dataoff, 731 - const struct nf_hook_state *state) 728 + static bool tcp_error(const struct tcphdr *th, 729 + struct sk_buff *skb, 730 + unsigned int dataoff, 731 + const struct nf_hook_state *state) 732 732 { 733 - const struct tcphdr *th; 734 - struct tcphdr _tcph; 735 733 unsigned int tcplen = skb->len - dataoff; 736 - u_int8_t tcpflags; 737 - 738 - /* Smaller that minimal TCP header? */ 739 - th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); 740 - if (th == NULL) { 741 - tcp_error_log(skb, state, "short packet"); 742 - return -NF_ACCEPT; 743 - } 734 + u8 tcpflags; 744 735 745 736 /* Not whole TCP header or malformed packet */ 746 737 if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { 747 738 tcp_error_log(skb, state, "truncated packet"); 748 - return -NF_ACCEPT; 739 + return true; 749 740 } 750 741 751 742 /* Checksum invalid? Ignore. ··· 748 757 state->hook == NF_INET_PRE_ROUTING && 749 758 nf_checksum(skb, state->hook, dataoff, IPPROTO_TCP, state->pf)) { 750 759 tcp_error_log(skb, state, "bad checksum"); 751 - return -NF_ACCEPT; 760 + return true; 752 761 } 753 762 754 763 /* Check TCP flags. */ 755 764 tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH)); 756 765 if (!tcp_valid_flags[tcpflags]) { 757 766 tcp_error_log(skb, state, "invalid tcp flag combination"); 758 - return -NF_ACCEPT; 767 + return true; 759 768 } 760 769 761 - return NF_ACCEPT; 770 + return false; 762 771 } 763 772 764 773 static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, ··· 852 861 853 862 th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); 854 863 if (th == NULL) 864 + return -NF_ACCEPT; 865 + 866 + if (tcp_error(th, skb, dataoff, state)) 855 867 return -NF_ACCEPT; 856 868 857 869 if (!nf_ct_is_confirmed(ct) && !tcp_new(ct, skb, dataoff, th)) ··· 1542 1548 .print_conntrack = tcp_print_conntrack, 1543 1549 #endif 1544 1550 .packet = tcp_packet, 1545 - .error = tcp_error, 1546 1551 .can_early_drop = tcp_can_early_drop, 1547 1552 #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 1548 1553 .to_nlattr = tcp_to_nlattr, ··· 1575 1582 .print_conntrack = tcp_print_conntrack, 1576 1583 #endif 1577 1584 .packet = tcp_packet, 1578 - .error = tcp_error, 1579 1585 .can_early_drop = tcp_can_early_drop, 1580 1586 #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 1581 1587 .nlattr_size = TCP_NLATTR_SIZE,