diff options
author | David S. Miller <davem@davemloft.net> | 2013-08-10 16:44:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-10 16:44:22 -0400 |
commit | 4209423c29a593f8a1fe1c3337d9ad7d52a1caa9 (patch) | |
tree | 3d60148ff0419da8bb1ffe1780716ee3c7094d8d /net | |
parent | 645359930231d5e78fd3296a38b98c1a658a7ade (diff) | |
parent | 356d7d88e088687b6578ca64601b0a2c9d145296 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says:
====================
The following patchset contains four netfilter fixes, they are:
* Fix possible invalid access and mangling of the TCPMSS option in
xt_TCPMSS. This was spotted by Julian Anastasov.
* Fix possible off by one access and mangling of the TCP packet in
xt_TCPOPTSTRIP, also spotted by Julian Anastasov.
* Fix possible information leak due to missing initialization of one
padding field of several structures that are included in nfqueue and
nflog netlink messages, from Dan Carpenter.
* Fix TCP window tracking with Fast Open, from Yuchung Cheng.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 12 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 6 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue_core.c | 5 | ||||
-rw-r--r-- | net/netfilter/xt_TCPMSS.c | 28 | ||||
-rw-r--r-- | net/netfilter/xt_TCPOPTSTRIP.c | 10 |
5 files changed, 39 insertions, 22 deletions
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 7dcc376eea5f..2f8010707d01 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -526,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct, | |||
526 | const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; | 526 | const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; |
527 | __u32 seq, ack, sack, end, win, swin; | 527 | __u32 seq, ack, sack, end, win, swin; |
528 | s16 receiver_offset; | 528 | s16 receiver_offset; |
529 | bool res; | 529 | bool res, in_recv_win; |
530 | 530 | ||
531 | /* | 531 | /* |
532 | * Get the required data from the packet. | 532 | * Get the required data from the packet. |
@@ -649,14 +649,18 @@ static bool tcp_in_window(const struct nf_conn *ct, | |||
649 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | 649 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, |
650 | receiver->td_scale); | 650 | receiver->td_scale); |
651 | 651 | ||
652 | /* Is the ending sequence in the receive window (if available)? */ | ||
653 | in_recv_win = !receiver->td_maxwin || | ||
654 | after(end, sender->td_end - receiver->td_maxwin - 1); | ||
655 | |||
652 | pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", | 656 | pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", |
653 | before(seq, sender->td_maxend + 1), | 657 | before(seq, sender->td_maxend + 1), |
654 | after(end, sender->td_end - receiver->td_maxwin - 1), | 658 | (in_recv_win ? 1 : 0), |
655 | before(sack, receiver->td_end + 1), | 659 | before(sack, receiver->td_end + 1), |
656 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); | 660 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); |
657 | 661 | ||
658 | if (before(seq, sender->td_maxend + 1) && | 662 | if (before(seq, sender->td_maxend + 1) && |
659 | after(end, sender->td_end - receiver->td_maxwin - 1) && | 663 | in_recv_win && |
660 | before(sack, receiver->td_end + 1) && | 664 | before(sack, receiver->td_end + 1) && |
661 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { | 665 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { |
662 | /* | 666 | /* |
@@ -725,7 +729,7 @@ static bool tcp_in_window(const struct nf_conn *ct, | |||
725 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, | 729 | nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, |
726 | "nf_ct_tcp: %s ", | 730 | "nf_ct_tcp: %s ", |
727 | before(seq, sender->td_maxend + 1) ? | 731 | before(seq, sender->td_maxend + 1) ? |
728 | after(end, sender->td_end - receiver->td_maxwin - 1) ? | 732 | in_recv_win ? |
729 | before(sack, receiver->td_end + 1) ? | 733 | before(sack, receiver->td_end + 1) ? |
730 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" | 734 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" |
731 | : "ACK is under the lower bound (possible overly delayed ACK)" | 735 | : "ACK is under the lower bound (possible overly delayed ACK)" |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 962e9792e317..d92cc317bf8b 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -419,6 +419,7 @@ __build_packet_message(struct nfnl_log_net *log, | |||
419 | nfmsg->version = NFNETLINK_V0; | 419 | nfmsg->version = NFNETLINK_V0; |
420 | nfmsg->res_id = htons(inst->group_num); | 420 | nfmsg->res_id = htons(inst->group_num); |
421 | 421 | ||
422 | memset(&pmsg, 0, sizeof(pmsg)); | ||
422 | pmsg.hw_protocol = skb->protocol; | 423 | pmsg.hw_protocol = skb->protocol; |
423 | pmsg.hook = hooknum; | 424 | pmsg.hook = hooknum; |
424 | 425 | ||
@@ -498,7 +499,10 @@ __build_packet_message(struct nfnl_log_net *log, | |||
498 | if (indev && skb->dev && | 499 | if (indev && skb->dev && |
499 | skb->mac_header != skb->network_header) { | 500 | skb->mac_header != skb->network_header) { |
500 | struct nfulnl_msg_packet_hw phw; | 501 | struct nfulnl_msg_packet_hw phw; |
501 | int len = dev_parse_header(skb, phw.hw_addr); | 502 | int len; |
503 | |||
504 | memset(&phw, 0, sizeof(phw)); | ||
505 | len = dev_parse_header(skb, phw.hw_addr); | ||
502 | if (len > 0) { | 506 | if (len > 0) { |
503 | phw.hw_addrlen = htons(len); | 507 | phw.hw_addrlen = htons(len); |
504 | if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw)) | 508 | if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw)) |
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 971ea145ab3e..8a703c3dd318 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c | |||
@@ -463,7 +463,10 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
463 | if (indev && entskb->dev && | 463 | if (indev && entskb->dev && |
464 | entskb->mac_header != entskb->network_header) { | 464 | entskb->mac_header != entskb->network_header) { |
465 | struct nfqnl_msg_packet_hw phw; | 465 | struct nfqnl_msg_packet_hw phw; |
466 | int len = dev_parse_header(entskb, phw.hw_addr); | 466 | int len; |
467 | |||
468 | memset(&phw, 0, sizeof(phw)); | ||
469 | len = dev_parse_header(entskb, phw.hw_addr); | ||
467 | if (len) { | 470 | if (len) { |
468 | phw.hw_addrlen = htons(len); | 471 | phw.hw_addrlen = htons(len); |
469 | if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw)) | 472 | if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw)) |
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 7011c71646f0..6113cc7efffc 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
@@ -52,7 +52,8 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
52 | { | 52 | { |
53 | const struct xt_tcpmss_info *info = par->targinfo; | 53 | const struct xt_tcpmss_info *info = par->targinfo; |
54 | struct tcphdr *tcph; | 54 | struct tcphdr *tcph; |
55 | unsigned int tcplen, i; | 55 | int len, tcp_hdrlen; |
56 | unsigned int i; | ||
56 | __be16 oldval; | 57 | __be16 oldval; |
57 | u16 newmss; | 58 | u16 newmss; |
58 | u8 *opt; | 59 | u8 *opt; |
@@ -64,11 +65,14 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
64 | if (!skb_make_writable(skb, skb->len)) | 65 | if (!skb_make_writable(skb, skb->len)) |
65 | return -1; | 66 | return -1; |
66 | 67 | ||
67 | tcplen = skb->len - tcphoff; | 68 | len = skb->len - tcphoff; |
69 | if (len < (int)sizeof(struct tcphdr)) | ||
70 | return -1; | ||
71 | |||
68 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); | 72 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); |
73 | tcp_hdrlen = tcph->doff * 4; | ||
69 | 74 | ||
70 | /* Header cannot be larger than the packet */ | 75 | if (len < tcp_hdrlen) |
71 | if (tcplen < tcph->doff*4) | ||
72 | return -1; | 76 | return -1; |
73 | 77 | ||
74 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { | 78 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { |
@@ -87,9 +91,8 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
87 | newmss = info->mss; | 91 | newmss = info->mss; |
88 | 92 | ||
89 | opt = (u_int8_t *)tcph; | 93 | opt = (u_int8_t *)tcph; |
90 | for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { | 94 | for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) { |
91 | if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && | 95 | if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) { |
92 | opt[i+1] == TCPOLEN_MSS) { | ||
93 | u_int16_t oldmss; | 96 | u_int16_t oldmss; |
94 | 97 | ||
95 | oldmss = (opt[i+2] << 8) | opt[i+3]; | 98 | oldmss = (opt[i+2] << 8) | opt[i+3]; |
@@ -112,9 +115,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
112 | } | 115 | } |
113 | 116 | ||
114 | /* There is data after the header so the option can't be added | 117 | /* There is data after the header so the option can't be added |
115 | without moving it, and doing so may make the SYN packet | 118 | * without moving it, and doing so may make the SYN packet |
116 | itself too large. Accept the packet unmodified instead. */ | 119 | * itself too large. Accept the packet unmodified instead. |
117 | if (tcplen > tcph->doff*4) | 120 | */ |
121 | if (len > tcp_hdrlen) | ||
118 | return 0; | 122 | return 0; |
119 | 123 | ||
120 | /* | 124 | /* |
@@ -143,10 +147,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
143 | newmss = min(newmss, (u16)1220); | 147 | newmss = min(newmss, (u16)1220); |
144 | 148 | ||
145 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); | 149 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); |
146 | memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); | 150 | memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr)); |
147 | 151 | ||
148 | inet_proto_csum_replace2(&tcph->check, skb, | 152 | inet_proto_csum_replace2(&tcph->check, skb, |
149 | htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); | 153 | htons(len), htons(len + TCPOLEN_MSS), 1); |
150 | opt[0] = TCPOPT_MSS; | 154 | opt[0] = TCPOPT_MSS; |
151 | opt[1] = TCPOLEN_MSS; | 155 | opt[1] = TCPOLEN_MSS; |
152 | opt[2] = (newmss & 0xff00) >> 8; | 156 | opt[2] = (newmss & 0xff00) >> 8; |
diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c index b68fa191710f..625fa1d636a0 100644 --- a/net/netfilter/xt_TCPOPTSTRIP.c +++ b/net/netfilter/xt_TCPOPTSTRIP.c | |||
@@ -38,7 +38,7 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb, | |||
38 | struct tcphdr *tcph; | 38 | struct tcphdr *tcph; |
39 | u_int16_t n, o; | 39 | u_int16_t n, o; |
40 | u_int8_t *opt; | 40 | u_int8_t *opt; |
41 | int len; | 41 | int len, tcp_hdrlen; |
42 | 42 | ||
43 | /* This is a fragment, no TCP header is available */ | 43 | /* This is a fragment, no TCP header is available */ |
44 | if (par->fragoff != 0) | 44 | if (par->fragoff != 0) |
@@ -52,7 +52,9 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb, | |||
52 | return NF_DROP; | 52 | return NF_DROP; |
53 | 53 | ||
54 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); | 54 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); |
55 | if (tcph->doff * 4 > len) | 55 | tcp_hdrlen = tcph->doff * 4; |
56 | |||
57 | if (len < tcp_hdrlen) | ||
56 | return NF_DROP; | 58 | return NF_DROP; |
57 | 59 | ||
58 | opt = (u_int8_t *)tcph; | 60 | opt = (u_int8_t *)tcph; |
@@ -61,10 +63,10 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb, | |||
61 | * Walk through all TCP options - if we find some option to remove, | 63 | * Walk through all TCP options - if we find some option to remove, |
62 | * set all octets to %TCPOPT_NOP and adjust checksum. | 64 | * set all octets to %TCPOPT_NOP and adjust checksum. |
63 | */ | 65 | */ |
64 | for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { | 66 | for (i = sizeof(struct tcphdr); i < tcp_hdrlen - 1; i += optl) { |
65 | optl = optlen(opt, i); | 67 | optl = optlen(opt, i); |
66 | 68 | ||
67 | if (i + optl > tcp_hdrlen(skb)) | 69 | if (i + optl > tcp_hdrlen) |
68 | break; | 70 | break; |
69 | 71 | ||
70 | if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) | 72 | if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) |