diff options
author | David S. Miller <davem@davemloft.net> | 2012-08-20 05:44:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-20 05:44:29 -0400 |
commit | 6c71bec66ae65305ba5c33c93aa722f21f092737 (patch) | |
tree | ab07e16e8047bea8343d6ad34f0d5377f369aef4 /net | |
parent | c0de08d04215031d68fa13af36f347a6cfa252ca (diff) | |
parent | 2614f86490122bf51eb7c12ec73927f1900f4e7d (diff) |
Merge git://1984.lsi.us.es/nf
Pable Neira Ayuso says:
====================
The following five patches contain fixes for 3.6-rc, they are:
* Two fixes for message parsing in the SIP conntrack helper, from
Patrick McHardy.
* One fix for the SIP helper introduced in the user-space cthelper
infrastructure, from Patrick McHardy.
* fix missing appropriate locking while modifying one conntrack entry
from the nfqueue integration code, from myself.
* fix possible access to uninitiliazed timer in the nf_conntrack
expectation infrastructure, from myself.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 9 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 29 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 7 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 92 |
4 files changed, 89 insertions, 48 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index ea4a23813d26..4ad9cf173992 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
148 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | 148 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
149 | hdr, NULL, &matchoff, &matchlen, | 149 | hdr, NULL, &matchoff, &matchlen, |
150 | &addr, &port) > 0) { | 150 | &addr, &port) > 0) { |
151 | unsigned int matchend, poff, plen, buflen, n; | 151 | unsigned int olen, matchend, poff, plen, buflen, n; |
152 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | 152 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; |
153 | 153 | ||
154 | /* We're only interested in headers related to this | 154 | /* We're only interested in headers related to this |
@@ -163,17 +163,18 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
163 | goto next; | 163 | goto next; |
164 | } | 164 | } |
165 | 165 | ||
166 | olen = *datalen; | ||
166 | if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, | 167 | if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, |
167 | &addr, port)) | 168 | &addr, port)) |
168 | return NF_DROP; | 169 | return NF_DROP; |
169 | 170 | ||
170 | matchend = matchoff + matchlen; | 171 | matchend = matchoff + matchlen + *datalen - olen; |
171 | 172 | ||
172 | /* The maddr= parameter (RFC 2361) specifies where to send | 173 | /* The maddr= parameter (RFC 2361) specifies where to send |
173 | * the reply. */ | 174 | * the reply. */ |
174 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, | 175 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
175 | "maddr=", &poff, &plen, | 176 | "maddr=", &poff, &plen, |
176 | &addr) > 0 && | 177 | &addr, true) > 0 && |
177 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && | 178 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && |
178 | addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { | 179 | addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { |
179 | buflen = sprintf(buffer, "%pI4", | 180 | buflen = sprintf(buffer, "%pI4", |
@@ -187,7 +188,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
187 | * from which the server received the request. */ | 188 | * from which the server received the request. */ |
188 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, | 189 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
189 | "received=", &poff, &plen, | 190 | "received=", &poff, &plen, |
190 | &addr) > 0 && | 191 | &addr, false) > 0 && |
191 | addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && | 192 | addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && |
192 | addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { | 193 | addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { |
193 | buflen = sprintf(buffer, "%pI4", | 194 | buflen = sprintf(buffer, "%pI4", |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 45cf602a76bc..527651a53a45 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -361,23 +361,6 @@ static void evict_oldest_expect(struct nf_conn *master, | |||
361 | } | 361 | } |
362 | } | 362 | } |
363 | 363 | ||
364 | static inline int refresh_timer(struct nf_conntrack_expect *i) | ||
365 | { | ||
366 | struct nf_conn_help *master_help = nfct_help(i->master); | ||
367 | const struct nf_conntrack_expect_policy *p; | ||
368 | |||
369 | if (!del_timer(&i->timeout)) | ||
370 | return 0; | ||
371 | |||
372 | p = &rcu_dereference_protected( | ||
373 | master_help->helper, | ||
374 | lockdep_is_held(&nf_conntrack_lock) | ||
375 | )->expect_policy[i->class]; | ||
376 | i->timeout.expires = jiffies + p->timeout * HZ; | ||
377 | add_timer(&i->timeout); | ||
378 | return 1; | ||
379 | } | ||
380 | |||
381 | static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | 364 | static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) |
382 | { | 365 | { |
383 | const struct nf_conntrack_expect_policy *p; | 366 | const struct nf_conntrack_expect_policy *p; |
@@ -386,7 +369,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | |||
386 | struct nf_conn_help *master_help = nfct_help(master); | 369 | struct nf_conn_help *master_help = nfct_help(master); |
387 | struct nf_conntrack_helper *helper; | 370 | struct nf_conntrack_helper *helper; |
388 | struct net *net = nf_ct_exp_net(expect); | 371 | struct net *net = nf_ct_exp_net(expect); |
389 | struct hlist_node *n; | 372 | struct hlist_node *n, *next; |
390 | unsigned int h; | 373 | unsigned int h; |
391 | int ret = 1; | 374 | int ret = 1; |
392 | 375 | ||
@@ -395,12 +378,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | |||
395 | goto out; | 378 | goto out; |
396 | } | 379 | } |
397 | h = nf_ct_expect_dst_hash(&expect->tuple); | 380 | h = nf_ct_expect_dst_hash(&expect->tuple); |
398 | hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) { | 381 | hlist_for_each_entry_safe(i, n, next, &net->ct.expect_hash[h], hnode) { |
399 | if (expect_matches(i, expect)) { | 382 | if (expect_matches(i, expect)) { |
400 | /* Refresh timer: if it's dying, ignore.. */ | 383 | if (del_timer(&i->timeout)) { |
401 | if (refresh_timer(i)) { | 384 | nf_ct_unlink_expect(i); |
402 | ret = 0; | 385 | nf_ct_expect_put(i); |
403 | goto out; | 386 | break; |
404 | } | 387 | } |
405 | } else if (expect_clash(i, expect)) { | 388 | } else if (expect_clash(i, expect)) { |
406 | ret = -EBUSY; | 389 | ret = -EBUSY; |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 14f67a2cbcb5..da4fc37a8578 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -1896,10 +1896,15 @@ static int | |||
1896 | ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct) | 1896 | ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct) |
1897 | { | 1897 | { |
1898 | struct nlattr *cda[CTA_MAX+1]; | 1898 | struct nlattr *cda[CTA_MAX+1]; |
1899 | int ret; | ||
1899 | 1900 | ||
1900 | nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy); | 1901 | nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy); |
1901 | 1902 | ||
1902 | return ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct); | 1903 | spin_lock_bh(&nf_conntrack_lock); |
1904 | ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct); | ||
1905 | spin_unlock_bh(&nf_conntrack_lock); | ||
1906 | |||
1907 | return ret; | ||
1903 | } | 1908 | } |
1904 | 1909 | ||
1905 | static struct nfq_ct_hook ctnetlink_nfqueue_hook = { | 1910 | static struct nfq_ct_hook ctnetlink_nfqueue_hook = { |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 758a1bacc126..5c0a112aeee6 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr, | |||
183 | return len + digits_len(ct, dptr, limit, shift); | 183 | return len + digits_len(ct, dptr, limit, shift); |
184 | } | 184 | } |
185 | 185 | ||
186 | static int parse_addr(const struct nf_conn *ct, const char *cp, | 186 | static int sip_parse_addr(const struct nf_conn *ct, const char *cp, |
187 | const char **endp, union nf_inet_addr *addr, | 187 | const char **endp, union nf_inet_addr *addr, |
188 | const char *limit) | 188 | const char *limit, bool delim) |
189 | { | 189 | { |
190 | const char *end; | 190 | const char *end; |
191 | int ret = 0; | 191 | int ret; |
192 | 192 | ||
193 | if (!ct) | 193 | if (!ct) |
194 | return 0; | 194 | return 0; |
@@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, | |||
197 | switch (nf_ct_l3num(ct)) { | 197 | switch (nf_ct_l3num(ct)) { |
198 | case AF_INET: | 198 | case AF_INET: |
199 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); | 199 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); |
200 | if (ret == 0) | ||
201 | return 0; | ||
200 | break; | 202 | break; |
201 | case AF_INET6: | 203 | case AF_INET6: |
204 | if (cp < limit && *cp == '[') | ||
205 | cp++; | ||
206 | else if (delim) | ||
207 | return 0; | ||
208 | |||
202 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); | 209 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); |
210 | if (ret == 0) | ||
211 | return 0; | ||
212 | |||
213 | if (end < limit && *end == ']') | ||
214 | end++; | ||
215 | else if (delim) | ||
216 | return 0; | ||
203 | break; | 217 | break; |
204 | default: | 218 | default: |
205 | BUG(); | 219 | BUG(); |
206 | } | 220 | } |
207 | 221 | ||
208 | if (ret == 0 || end == cp) | ||
209 | return 0; | ||
210 | if (endp) | 222 | if (endp) |
211 | *endp = end; | 223 | *endp = end; |
212 | return 1; | 224 | return 1; |
@@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, | |||
219 | union nf_inet_addr addr; | 231 | union nf_inet_addr addr; |
220 | const char *aux = dptr; | 232 | const char *aux = dptr; |
221 | 233 | ||
222 | if (!parse_addr(ct, dptr, &dptr, &addr, limit)) { | 234 | if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) { |
223 | pr_debug("ip: %s parse failed.!\n", dptr); | 235 | pr_debug("ip: %s parse failed.!\n", dptr); |
224 | return 0; | 236 | return 0; |
225 | } | 237 | } |
@@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct, | |||
296 | return 0; | 308 | return 0; |
297 | dptr += shift; | 309 | dptr += shift; |
298 | 310 | ||
299 | if (!parse_addr(ct, dptr, &end, addr, limit)) | 311 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) |
300 | return -1; | 312 | return -1; |
301 | if (end < limit && *end == ':') { | 313 | if (end < limit && *end == ':') { |
302 | end++; | 314 | end++; |
@@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, | |||
550 | if (ret == 0) | 562 | if (ret == 0) |
551 | return ret; | 563 | return ret; |
552 | 564 | ||
553 | if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit)) | 565 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) |
554 | return -1; | 566 | return -1; |
555 | if (*c == ':') { | 567 | if (*c == ':') { |
556 | c++; | 568 | c++; |
@@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, | |||
599 | unsigned int dataoff, unsigned int datalen, | 611 | unsigned int dataoff, unsigned int datalen, |
600 | const char *name, | 612 | const char *name, |
601 | unsigned int *matchoff, unsigned int *matchlen, | 613 | unsigned int *matchoff, unsigned int *matchlen, |
602 | union nf_inet_addr *addr) | 614 | union nf_inet_addr *addr, bool delim) |
603 | { | 615 | { |
604 | const char *limit = dptr + datalen; | 616 | const char *limit = dptr + datalen; |
605 | const char *start, *end; | 617 | const char *start, *end; |
@@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, | |||
613 | return 0; | 625 | return 0; |
614 | 626 | ||
615 | start += strlen(name); | 627 | start += strlen(name); |
616 | if (!parse_addr(ct, start, &end, addr, limit)) | 628 | if (!sip_parse_addr(ct, start, &end, addr, limit, delim)) |
617 | return 0; | 629 | return 0; |
618 | *matchoff = start - dptr; | 630 | *matchoff = start - dptr; |
619 | *matchlen = end - start; | 631 | *matchlen = end - start; |
@@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, | |||
675 | return 1; | 687 | return 1; |
676 | } | 688 | } |
677 | 689 | ||
690 | static int sdp_parse_addr(const struct nf_conn *ct, const char *cp, | ||
691 | const char **endp, union nf_inet_addr *addr, | ||
692 | const char *limit) | ||
693 | { | ||
694 | const char *end; | ||
695 | int ret; | ||
696 | |||
697 | memset(addr, 0, sizeof(*addr)); | ||
698 | switch (nf_ct_l3num(ct)) { | ||
699 | case AF_INET: | ||
700 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); | ||
701 | break; | ||
702 | case AF_INET6: | ||
703 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); | ||
704 | break; | ||
705 | default: | ||
706 | BUG(); | ||
707 | } | ||
708 | |||
709 | if (ret == 0) | ||
710 | return 0; | ||
711 | if (endp) | ||
712 | *endp = end; | ||
713 | return 1; | ||
714 | } | ||
715 | |||
716 | /* skip ip address. returns its length. */ | ||
717 | static int sdp_addr_len(const struct nf_conn *ct, const char *dptr, | ||
718 | const char *limit, int *shift) | ||
719 | { | ||
720 | union nf_inet_addr addr; | ||
721 | const char *aux = dptr; | ||
722 | |||
723 | if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) { | ||
724 | pr_debug("ip: %s parse failed.!\n", dptr); | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | return dptr - aux; | ||
729 | } | ||
730 | |||
678 | /* SDP header parsing: a SDP session description contains an ordered set of | 731 | /* SDP header parsing: a SDP session description contains an ordered set of |
679 | * headers, starting with a section containing general session parameters, | 732 | * headers, starting with a section containing general session parameters, |
680 | * optionally followed by multiple media descriptions. | 733 | * optionally followed by multiple media descriptions. |
@@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, | |||
686 | */ | 739 | */ |
687 | static const struct sip_header ct_sdp_hdrs[] = { | 740 | static const struct sip_header ct_sdp_hdrs[] = { |
688 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), | 741 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), |
689 | [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), | 742 | [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len), |
690 | [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), | 743 | [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len), |
691 | [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), | 744 | [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len), |
692 | [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), | 745 | [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len), |
693 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), | 746 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), |
694 | }; | 747 | }; |
695 | 748 | ||
@@ -775,8 +828,8 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, | |||
775 | if (ret <= 0) | 828 | if (ret <= 0) |
776 | return ret; | 829 | return ret; |
777 | 830 | ||
778 | if (!parse_addr(ct, dptr + *matchoff, NULL, addr, | 831 | if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr, |
779 | dptr + *matchoff + *matchlen)) | 832 | dptr + *matchoff + *matchlen)) |
780 | return -1; | 833 | return -1; |
781 | return 1; | 834 | return 1; |
782 | } | 835 | } |
@@ -1515,7 +1568,6 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, | |||
1515 | } | 1568 | } |
1516 | 1569 | ||
1517 | static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; | 1570 | static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; |
1518 | static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly; | ||
1519 | 1571 | ||
1520 | static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { | 1572 | static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { |
1521 | [SIP_EXPECT_SIGNALLING] = { | 1573 | [SIP_EXPECT_SIGNALLING] = { |
@@ -1585,9 +1637,9 @@ static int __init nf_conntrack_sip_init(void) | |||
1585 | sip[i][j].me = THIS_MODULE; | 1637 | sip[i][j].me = THIS_MODULE; |
1586 | 1638 | ||
1587 | if (ports[i] == SIP_PORT) | 1639 | if (ports[i] == SIP_PORT) |
1588 | sprintf(sip_names[i][j], "sip"); | 1640 | sprintf(sip[i][j].name, "sip"); |
1589 | else | 1641 | else |
1590 | sprintf(sip_names[i][j], "sip-%u", i); | 1642 | sprintf(sip[i][j].name, "sip-%u", i); |
1591 | 1643 | ||
1592 | pr_debug("port #%u: %u\n", i, ports[i]); | 1644 | pr_debug("port #%u: %u\n", i, ports[i]); |
1593 | 1645 | ||