Commit 6c71bec66ae65305ba5c33c93aa722f21f092737
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>
Showing 5 changed files Side-by-side Diff
include/linux/netfilter/nf_conntrack_sip.h
... | ... | @@ -164,7 +164,7 @@ |
164 | 164 | unsigned int dataoff, unsigned int datalen, |
165 | 165 | const char *name, |
166 | 166 | unsigned int *matchoff, unsigned int *matchlen, |
167 | - union nf_inet_addr *addr); | |
167 | + union nf_inet_addr *addr, bool delim); | |
168 | 168 | extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, |
169 | 169 | unsigned int off, unsigned int datalen, |
170 | 170 | const char *name, |
net/ipv4/netfilter/nf_nat_sip.c
... | ... | @@ -148,7 +148,7 @@ |
148 | 148 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
149 | 149 | hdr, NULL, &matchoff, &matchlen, |
150 | 150 | &addr, &port) > 0) { |
151 | - unsigned int matchend, poff, plen, buflen, n; | |
151 | + unsigned int olen, matchend, poff, plen, buflen, n; | |
152 | 152 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; |
153 | 153 | |
154 | 154 | /* We're only interested in headers related to this |
155 | 155 | |
156 | 156 | |
... | ... | @@ -163,17 +163,18 @@ |
163 | 163 | goto next; |
164 | 164 | } |
165 | 165 | |
166 | + olen = *datalen; | |
166 | 167 | if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, |
167 | 168 | &addr, port)) |
168 | 169 | return NF_DROP; |
169 | 170 | |
170 | - matchend = matchoff + matchlen; | |
171 | + matchend = matchoff + matchlen + *datalen - olen; | |
171 | 172 | |
172 | 173 | /* The maddr= parameter (RFC 2361) specifies where to send |
173 | 174 | * the reply. */ |
174 | 175 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
175 | 176 | "maddr=", &poff, &plen, |
176 | - &addr) > 0 && | |
177 | + &addr, true) > 0 && | |
177 | 178 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && |
178 | 179 | addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { |
179 | 180 | buflen = sprintf(buffer, "%pI4", |
... | ... | @@ -187,7 +188,7 @@ |
187 | 188 | * from which the server received the request. */ |
188 | 189 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
189 | 190 | "received=", &poff, &plen, |
190 | - &addr) > 0 && | |
191 | + &addr, false) > 0 && | |
191 | 192 | addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && |
192 | 193 | addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { |
193 | 194 | buflen = sprintf(buffer, "%pI4", |
net/netfilter/nf_conntrack_expect.c
... | ... | @@ -361,23 +361,6 @@ |
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 | 364 | static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) |
382 | 365 | { |
383 | 366 | const struct nf_conntrack_expect_policy *p; |
... | ... | @@ -386,7 +369,7 @@ |
386 | 369 | struct nf_conn_help *master_help = nfct_help(master); |
387 | 370 | struct nf_conntrack_helper *helper; |
388 | 371 | struct net *net = nf_ct_exp_net(expect); |
389 | - struct hlist_node *n; | |
372 | + struct hlist_node *n, *next; | |
390 | 373 | unsigned int h; |
391 | 374 | int ret = 1; |
392 | 375 | |
393 | 376 | |
... | ... | @@ -395,12 +378,12 @@ |
395 | 378 | goto out; |
396 | 379 | } |
397 | 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 | 382 | if (expect_matches(i, expect)) { |
400 | - /* Refresh timer: if it's dying, ignore.. */ | |
401 | - if (refresh_timer(i)) { | |
402 | - ret = 0; | |
403 | - goto out; | |
383 | + if (del_timer(&i->timeout)) { | |
384 | + nf_ct_unlink_expect(i); | |
385 | + nf_ct_expect_put(i); | |
386 | + break; | |
404 | 387 | } |
405 | 388 | } else if (expect_clash(i, expect)) { |
406 | 389 | ret = -EBUSY; |
net/netfilter/nf_conntrack_netlink.c
... | ... | @@ -1896,10 +1896,15 @@ |
1896 | 1896 | ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct) |
1897 | 1897 | { |
1898 | 1898 | struct nlattr *cda[CTA_MAX+1]; |
1899 | + int ret; | |
1899 | 1900 | |
1900 | 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 | 1910 | static struct nfq_ct_hook ctnetlink_nfqueue_hook = { |
net/netfilter/nf_conntrack_sip.c
... | ... | @@ -183,12 +183,12 @@ |
183 | 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, | |
187 | - const char **endp, union nf_inet_addr *addr, | |
188 | - const char *limit) | |
186 | +static int sip_parse_addr(const struct nf_conn *ct, const char *cp, | |
187 | + const char **endp, union nf_inet_addr *addr, | |
188 | + const char *limit, bool delim) | |
189 | 189 | { |
190 | 190 | const char *end; |
191 | - int ret = 0; | |
191 | + int ret; | |
192 | 192 | |
193 | 193 | if (!ct) |
194 | 194 | return 0; |
195 | 195 | |
196 | 196 | |
197 | 197 | |
... | ... | @@ -197,16 +197,28 @@ |
197 | 197 | switch (nf_ct_l3num(ct)) { |
198 | 198 | case AF_INET: |
199 | 199 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); |
200 | + if (ret == 0) | |
201 | + return 0; | |
200 | 202 | break; |
201 | 203 | case AF_INET6: |
204 | + if (cp < limit && *cp == '[') | |
205 | + cp++; | |
206 | + else if (delim) | |
207 | + return 0; | |
208 | + | |
202 | 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 | 217 | break; |
204 | 218 | default: |
205 | 219 | BUG(); |
206 | 220 | } |
207 | 221 | |
208 | - if (ret == 0 || end == cp) | |
209 | - return 0; | |
210 | 222 | if (endp) |
211 | 223 | *endp = end; |
212 | 224 | return 1; |
... | ... | @@ -219,7 +231,7 @@ |
219 | 231 | union nf_inet_addr addr; |
220 | 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 | 235 | pr_debug("ip: %s parse failed.!\n", dptr); |
224 | 236 | return 0; |
225 | 237 | } |
... | ... | @@ -296,7 +308,7 @@ |
296 | 308 | return 0; |
297 | 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 | 312 | return -1; |
301 | 313 | if (end < limit && *end == ':') { |
302 | 314 | end++; |
... | ... | @@ -550,7 +562,7 @@ |
550 | 562 | if (ret == 0) |
551 | 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 | 566 | return -1; |
555 | 567 | if (*c == ':') { |
556 | 568 | c++; |
... | ... | @@ -599,7 +611,7 @@ |
599 | 611 | unsigned int dataoff, unsigned int datalen, |
600 | 612 | const char *name, |
601 | 613 | unsigned int *matchoff, unsigned int *matchlen, |
602 | - union nf_inet_addr *addr) | |
614 | + union nf_inet_addr *addr, bool delim) | |
603 | 615 | { |
604 | 616 | const char *limit = dptr + datalen; |
605 | 617 | const char *start, *end; |
... | ... | @@ -613,7 +625,7 @@ |
613 | 625 | return 0; |
614 | 626 | |
615 | 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 | 629 | return 0; |
618 | 630 | *matchoff = start - dptr; |
619 | 631 | *matchlen = end - start; |
... | ... | @@ -675,6 +687,47 @@ |
675 | 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 | 731 | /* SDP header parsing: a SDP session description contains an ordered set of |
679 | 732 | * headers, starting with a section containing general session parameters, |
680 | 733 | * optionally followed by multiple media descriptions. |
... | ... | @@ -686,10 +739,10 @@ |
686 | 739 | */ |
687 | 740 | static const struct sip_header ct_sdp_hdrs[] = { |
688 | 741 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), |
689 | - [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), | |
690 | - [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), | |
691 | - [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), | |
692 | - [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), | |
742 | + [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len), | |
743 | + [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len), | |
744 | + [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len), | |
745 | + [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len), | |
693 | 746 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), |
694 | 747 | }; |
695 | 748 | |
... | ... | @@ -775,8 +828,8 @@ |
775 | 828 | if (ret <= 0) |
776 | 829 | return ret; |
777 | 830 | |
778 | - if (!parse_addr(ct, dptr + *matchoff, NULL, addr, | |
779 | - dptr + *matchoff + *matchlen)) | |
831 | + if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr, | |
832 | + dptr + *matchoff + *matchlen)) | |
780 | 833 | return -1; |
781 | 834 | return 1; |
782 | 835 | } |
... | ... | @@ -1515,7 +1568,6 @@ |
1515 | 1568 | } |
1516 | 1569 | |
1517 | 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 | 1572 | static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { |
1521 | 1573 | [SIP_EXPECT_SIGNALLING] = { |
1522 | 1574 | |
... | ... | @@ -1585,9 +1637,9 @@ |
1585 | 1637 | sip[i][j].me = THIS_MODULE; |
1586 | 1638 | |
1587 | 1639 | if (ports[i] == SIP_PORT) |
1588 | - sprintf(sip_names[i][j], "sip"); | |
1640 | + sprintf(sip[i][j].name, "sip"); | |
1589 | 1641 | else |
1590 | - sprintf(sip_names[i][j], "sip-%u", i); | |
1642 | + sprintf(sip[i][j].name, "sip-%u", i); | |
1591 | 1643 | |
1592 | 1644 | pr_debug("port #%u: %u\n", i, ports[i]); |
1593 | 1645 |