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>
This commit is contained in:
David S. Miller 2013-08-10 13:44:22 -07:00
commit 4209423c29
5 changed files with 40 additions and 23 deletions

View file

@ -526,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
__u32 seq, ack, sack, end, win, swin; __u32 seq, ack, sack, end, win, swin;
s16 receiver_offset; s16 receiver_offset;
bool res; bool res, in_recv_win;
/* /*
* Get the required data from the packet. * Get the required data from the packet.
@ -649,14 +649,18 @@ static bool tcp_in_window(const struct nf_conn *ct,
receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
receiver->td_scale); receiver->td_scale);
/* Is the ending sequence in the receive window (if available)? */
in_recv_win = !receiver->td_maxwin ||
after(end, sender->td_end - receiver->td_maxwin - 1);
pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
before(seq, sender->td_maxend + 1), before(seq, sender->td_maxend + 1),
after(end, sender->td_end - receiver->td_maxwin - 1), (in_recv_win ? 1 : 0),
before(sack, receiver->td_end + 1), before(sack, receiver->td_end + 1),
after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1));
if (before(seq, sender->td_maxend + 1) && if (before(seq, sender->td_maxend + 1) &&
after(end, sender->td_end - receiver->td_maxwin - 1) && in_recv_win &&
before(sack, receiver->td_end + 1) && before(sack, receiver->td_end + 1) &&
after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) {
/* /*
@ -725,7 +729,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: %s ", "nf_ct_tcp: %s ",
before(seq, sender->td_maxend + 1) ? before(seq, sender->td_maxend + 1) ?
after(end, sender->td_end - receiver->td_maxwin - 1) ? in_recv_win ?
before(sack, receiver->td_end + 1) ? before(sack, receiver->td_end + 1) ?
after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG"
: "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is under the lower bound (possible overly delayed ACK)"

View file

@ -419,6 +419,7 @@ __build_packet_message(struct nfnl_log_net *log,
nfmsg->version = NFNETLINK_V0; nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = htons(inst->group_num); nfmsg->res_id = htons(inst->group_num);
memset(&pmsg, 0, sizeof(pmsg));
pmsg.hw_protocol = skb->protocol; pmsg.hw_protocol = skb->protocol;
pmsg.hook = hooknum; pmsg.hook = hooknum;
@ -498,7 +499,10 @@ __build_packet_message(struct nfnl_log_net *log,
if (indev && skb->dev && if (indev && skb->dev &&
skb->mac_header != skb->network_header) { skb->mac_header != skb->network_header) {
struct nfulnl_msg_packet_hw phw; struct nfulnl_msg_packet_hw phw;
int len = dev_parse_header(skb, phw.hw_addr); int len;
memset(&phw, 0, sizeof(phw));
len = dev_parse_header(skb, phw.hw_addr);
if (len > 0) { if (len > 0) {
phw.hw_addrlen = htons(len); phw.hw_addrlen = htons(len);
if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw)) if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw))

View file

@ -463,7 +463,10 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
if (indev && entskb->dev && if (indev && entskb->dev &&
entskb->mac_header != entskb->network_header) { entskb->mac_header != entskb->network_header) {
struct nfqnl_msg_packet_hw phw; struct nfqnl_msg_packet_hw phw;
int len = dev_parse_header(entskb, phw.hw_addr); int len;
memset(&phw, 0, sizeof(phw));
len = dev_parse_header(entskb, phw.hw_addr);
if (len) { if (len) {
phw.hw_addrlen = htons(len); phw.hw_addrlen = htons(len);
if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw)) if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))

View file

@ -52,7 +52,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
{ {
const struct xt_tcpmss_info *info = par->targinfo; const struct xt_tcpmss_info *info = par->targinfo;
struct tcphdr *tcph; struct tcphdr *tcph;
unsigned int tcplen, i; int len, tcp_hdrlen;
unsigned int i;
__be16 oldval; __be16 oldval;
u16 newmss; u16 newmss;
u8 *opt; u8 *opt;
@ -64,11 +65,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
if (!skb_make_writable(skb, skb->len)) if (!skb_make_writable(skb, skb->len))
return -1; return -1;
tcplen = skb->len - tcphoff; len = skb->len - tcphoff;
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); if (len < (int)sizeof(struct tcphdr))
return -1;
/* Header cannot be larger than the packet */ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
if (tcplen < tcph->doff*4) tcp_hdrlen = tcph->doff * 4;
if (len < tcp_hdrlen)
return -1; return -1;
if (info->mss == XT_TCPMSS_CLAMP_PMTU) { if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
@ -87,9 +91,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
newmss = info->mss; newmss = info->mss;
opt = (u_int8_t *)tcph; opt = (u_int8_t *)tcph;
for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
opt[i+1] == TCPOLEN_MSS) {
u_int16_t oldmss; u_int16_t oldmss;
oldmss = (opt[i+2] << 8) | opt[i+3]; oldmss = (opt[i+2] << 8) | opt[i+3];
@ -112,9 +115,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
} }
/* There is data after the header so the option can't be added /* There is data after the header so the option can't be added
without moving it, and doing so may make the SYN packet * without moving it, and doing so may make the SYN packet
itself too large. Accept the packet unmodified instead. */ * itself too large. Accept the packet unmodified instead.
if (tcplen > tcph->doff*4) */
if (len > tcp_hdrlen)
return 0; return 0;
/* /*
@ -143,10 +147,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
newmss = min(newmss, (u16)1220); newmss = min(newmss, (u16)1220);
opt = (u_int8_t *)tcph + sizeof(struct tcphdr); opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));
inet_proto_csum_replace2(&tcph->check, skb, inet_proto_csum_replace2(&tcph->check, skb,
htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); htons(len), htons(len + TCPOLEN_MSS), 1);
opt[0] = TCPOPT_MSS; opt[0] = TCPOPT_MSS;
opt[1] = TCPOLEN_MSS; opt[1] = TCPOLEN_MSS;
opt[2] = (newmss & 0xff00) >> 8; opt[2] = (newmss & 0xff00) >> 8;

View file

@ -38,7 +38,7 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
struct tcphdr *tcph; struct tcphdr *tcph;
u_int16_t n, o; u_int16_t n, o;
u_int8_t *opt; u_int8_t *opt;
int len; int len, tcp_hdrlen;
/* This is a fragment, no TCP header is available */ /* This is a fragment, no TCP header is available */
if (par->fragoff != 0) if (par->fragoff != 0)
@ -52,7 +52,9 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
return NF_DROP; return NF_DROP;
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
if (tcph->doff * 4 > len) tcp_hdrlen = tcph->doff * 4;
if (len < tcp_hdrlen)
return NF_DROP; return NF_DROP;
opt = (u_int8_t *)tcph; opt = (u_int8_t *)tcph;
@ -61,10 +63,10 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
* Walk through all TCP options - if we find some option to remove, * Walk through all TCP options - if we find some option to remove,
* set all octets to %TCPOPT_NOP and adjust checksum. * set all octets to %TCPOPT_NOP and adjust checksum.
*/ */
for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { for (i = sizeof(struct tcphdr); i < tcp_hdrlen - 1; i += optl) {
optl = optlen(opt, i); optl = optlen(opt, i);
if (i + optl > tcp_hdrlen(skb)) if (i + optl > tcp_hdrlen)
break; break;
if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i]))