Commit 6c71bec6 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents c0de08d0 2614f864
...@@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr ...@@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr
unsigned int dataoff, unsigned int datalen, unsigned int dataoff, unsigned int datalen,
const char *name, const char *name,
unsigned int *matchoff, unsigned int *matchlen, unsigned int *matchoff, unsigned int *matchlen,
union nf_inet_addr *addr); union nf_inet_addr *addr, bool delim);
extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
unsigned int off, unsigned int datalen, unsigned int off, unsigned int datalen,
const char *name, const char *name,
......
...@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, ...@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
hdr, NULL, &matchoff, &matchlen, hdr, NULL, &matchoff, &matchlen,
&addr, &port) > 0) { &addr, &port) > 0) {
unsigned int matchend, poff, plen, buflen, n; unsigned int olen, matchend, poff, plen, buflen, n;
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
/* We're only interested in headers related to this /* 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,17 +163,18 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
goto next; goto next;
} }
olen = *datalen;
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port)) &addr, port))
return NF_DROP; return NF_DROP;
matchend = matchoff + matchlen; matchend = matchoff + matchlen + *datalen - olen;
/* The maddr= parameter (RFC 2361) specifies where to send /* The maddr= parameter (RFC 2361) specifies where to send
* the reply. */ * the reply. */
if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
"maddr=", &poff, &plen, "maddr=", &poff, &plen,
&addr) > 0 && &addr, true) > 0 &&
addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
buflen = sprintf(buffer, "%pI4", buflen = sprintf(buffer, "%pI4",
...@@ -187,7 +188,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, ...@@ -187,7 +188,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
* from which the server received the request. */ * from which the server received the request. */
if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
"received=", &poff, &plen, "received=", &poff, &plen,
&addr) > 0 && &addr, false) > 0 &&
addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
buflen = sprintf(buffer, "%pI4", buflen = sprintf(buffer, "%pI4",
......
...@@ -361,23 +361,6 @@ static void evict_oldest_expect(struct nf_conn *master, ...@@ -361,23 +361,6 @@ static void evict_oldest_expect(struct nf_conn *master,
} }
} }
static inline int refresh_timer(struct nf_conntrack_expect *i)
{
struct nf_conn_help *master_help = nfct_help(i->master);
const struct nf_conntrack_expect_policy *p;
if (!del_timer(&i->timeout))
return 0;
p = &rcu_dereference_protected(
master_help->helper,
lockdep_is_held(&nf_conntrack_lock)
)->expect_policy[i->class];
i->timeout.expires = jiffies + p->timeout * HZ;
add_timer(&i->timeout);
return 1;
}
static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
{ {
const struct nf_conntrack_expect_policy *p; const struct nf_conntrack_expect_policy *p;
...@@ -386,7 +369,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) ...@@ -386,7 +369,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
struct nf_conn_help *master_help = nfct_help(master); struct nf_conn_help *master_help = nfct_help(master);
struct nf_conntrack_helper *helper; struct nf_conntrack_helper *helper;
struct net *net = nf_ct_exp_net(expect); struct net *net = nf_ct_exp_net(expect);
struct hlist_node *n; struct hlist_node *n, *next;
unsigned int h; unsigned int h;
int ret = 1; int ret = 1;
...@@ -395,12 +378,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) ...@@ -395,12 +378,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
goto out; goto out;
} }
h = nf_ct_expect_dst_hash(&expect->tuple); h = nf_ct_expect_dst_hash(&expect->tuple);
hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) { hlist_for_each_entry_safe(i, n, next, &net->ct.expect_hash[h], hnode) {
if (expect_matches(i, expect)) { if (expect_matches(i, expect)) {
/* Refresh timer: if it's dying, ignore.. */ if (del_timer(&i->timeout)) {
if (refresh_timer(i)) { nf_ct_unlink_expect(i);
ret = 0; nf_ct_expect_put(i);
goto out; break;
} }
} else if (expect_clash(i, expect)) { } else if (expect_clash(i, expect)) {
ret = -EBUSY; ret = -EBUSY;
......
...@@ -1896,10 +1896,15 @@ static int ...@@ -1896,10 +1896,15 @@ static int
ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct) ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
{ {
struct nlattr *cda[CTA_MAX+1]; struct nlattr *cda[CTA_MAX+1];
int ret;
nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy); nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
return ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct); spin_lock_bh(&nf_conntrack_lock);
ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
spin_unlock_bh(&nf_conntrack_lock);
return ret;
} }
static struct nfq_ct_hook ctnetlink_nfqueue_hook = { static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
......
...@@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr, ...@@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr,
return len + digits_len(ct, dptr, limit, shift); return len + digits_len(ct, dptr, limit, shift);
} }
static int parse_addr(const struct nf_conn *ct, const char *cp, static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
const char **endp, union nf_inet_addr *addr, const char **endp, union nf_inet_addr *addr,
const char *limit) const char *limit, bool delim)
{ {
const char *end; const char *end;
int ret = 0; int ret;
if (!ct) if (!ct)
return 0; return 0;
...@@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, ...@@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp,
switch (nf_ct_l3num(ct)) { switch (nf_ct_l3num(ct)) {
case AF_INET: case AF_INET:
ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
if (ret == 0)
return 0;
break; break;
case AF_INET6: case AF_INET6:
if (cp < limit && *cp == '[')
cp++;
else if (delim)
return 0;
ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
if (ret == 0)
return 0;
if (end < limit && *end == ']')
end++;
else if (delim)
return 0;
break; break;
default: default:
BUG(); BUG();
} }
if (ret == 0 || end == cp)
return 0;
if (endp) if (endp)
*endp = end; *endp = end;
return 1; return 1;
...@@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, ...@@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
union nf_inet_addr addr; union nf_inet_addr addr;
const char *aux = dptr; const char *aux = dptr;
if (!parse_addr(ct, dptr, &dptr, &addr, limit)) { if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) {
pr_debug("ip: %s parse failed.!\n", dptr); pr_debug("ip: %s parse failed.!\n", dptr);
return 0; return 0;
} }
...@@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct, ...@@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct,
return 0; return 0;
dptr += shift; dptr += shift;
if (!parse_addr(ct, dptr, &end, addr, limit)) if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
return -1; return -1;
if (end < limit && *end == ':') { if (end < limit && *end == ':') {
end++; end++;
...@@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, ...@@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
if (ret == 0) if (ret == 0)
return ret; return ret;
if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit)) if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
return -1; return -1;
if (*c == ':') { if (*c == ':') {
c++; c++;
...@@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, ...@@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
unsigned int dataoff, unsigned int datalen, unsigned int dataoff, unsigned int datalen,
const char *name, const char *name,
unsigned int *matchoff, unsigned int *matchlen, unsigned int *matchoff, unsigned int *matchlen,
union nf_inet_addr *addr) union nf_inet_addr *addr, bool delim)
{ {
const char *limit = dptr + datalen; const char *limit = dptr + datalen;
const char *start, *end; const char *start, *end;
...@@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, ...@@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
return 0; return 0;
start += strlen(name); start += strlen(name);
if (!parse_addr(ct, start, &end, addr, limit)) if (!sip_parse_addr(ct, start, &end, addr, limit, delim))
return 0; return 0;
*matchoff = start - dptr; *matchoff = start - dptr;
*matchlen = end - start; *matchlen = end - start;
...@@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, ...@@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
return 1; return 1;
} }
static int sdp_parse_addr(const struct nf_conn *ct, const char *cp,
const char **endp, union nf_inet_addr *addr,
const char *limit)
{
const char *end;
int ret;
memset(addr, 0, sizeof(*addr));
switch (nf_ct_l3num(ct)) {
case AF_INET:
ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
break;
case AF_INET6:
ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
break;
default:
BUG();
}
if (ret == 0)
return 0;
if (endp)
*endp = end;
return 1;
}
/* skip ip address. returns its length. */
static int sdp_addr_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
{
union nf_inet_addr addr;
const char *aux = dptr;
if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) {
pr_debug("ip: %s parse failed.!\n", dptr);
return 0;
}
return dptr - aux;
}
/* SDP header parsing: a SDP session description contains an ordered set of /* SDP header parsing: a SDP session description contains an ordered set of
* headers, starting with a section containing general session parameters, * headers, starting with a section containing general session parameters,
* optionally followed by multiple media descriptions. * optionally followed by multiple media descriptions.
...@@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, ...@@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
*/ */
static const struct sip_header ct_sdp_hdrs[] = { static const struct sip_header ct_sdp_hdrs[] = {
[SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len),
[SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len),
[SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len),
[SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len),
[SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len),
[SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len),
}; };
...@@ -775,8 +828,8 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, ...@@ -775,8 +828,8 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr,
if (ret <= 0) if (ret <= 0)
return ret; return ret;
if (!parse_addr(ct, dptr + *matchoff, NULL, addr, if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr,
dptr + *matchoff + *matchlen)) dptr + *matchoff + *matchlen))
return -1; return -1;
return 1; return 1;
} }
...@@ -1515,7 +1568,6 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, ...@@ -1515,7 +1568,6 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff,
} }
static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly;
static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly;
static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
[SIP_EXPECT_SIGNALLING] = { [SIP_EXPECT_SIGNALLING] = {
...@@ -1585,9 +1637,9 @@ static int __init nf_conntrack_sip_init(void) ...@@ -1585,9 +1637,9 @@ static int __init nf_conntrack_sip_init(void)
sip[i][j].me = THIS_MODULE; sip[i][j].me = THIS_MODULE;
if (ports[i] == SIP_PORT) if (ports[i] == SIP_PORT)
sprintf(sip_names[i][j], "sip"); sprintf(sip[i][j].name, "sip");
else else
sprintf(sip_names[i][j], "sip-%u", i); sprintf(sip[i][j].name, "sip-%u", i);
pr_debug("port #%u: %u\n", i, ports[i]); pr_debug("port #%u: %u\n", i, ports[i]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment