summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2013-07-06 14:04:24 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2013-07-06 15:17:26 +0200
commit479a37a549abf197ce59a4ae1666d8cba80fe977 (patch)
tree7fb43723c0fba13d72f6bf30351fde7e5da7b7ec
parente2c6576e775652c35d336afa0551676339c6a793 (diff)
downloadconntrack-tools-479a37a549abf197ce59a4ae1666d8cba80fe977.tar.gz
conntrack-tools-479a37a549abf197ce59a4ae1666d8cba80fe977.zip
conntrackd: fix crash with IPv6 expectation in the filtering code
Jul 5 00:41:06 sen-fw1 kernel: [274422.060695] conntrackd[4821]: segfault at 0 ip 000000000040c660 sp 00007fffebb098a8 error 4 in conntrackd[400000+3d000] > #0 0x000000000040f217 in jhash2 (k=0x0, length=4, initval=0) at ../include/jhash.h:99 > a = 2654435769 b = 2654435769 c = 0 len = 4 > #1 0x000000000040f564 in ct_filter_hash6 (data=0x0, table=0x16ef630) at filter.c:57 > #2 0x000000000040ad34 in hashtable_hash (table=0x16ef630, data=0x0) at hash.c:63 > #3 0x000000000040fd19 in __ct_filter_test_ipv6 (f=0x16eeba0, ct=0x1703760) at filter.c:265 > id_src = 51 id_dst = 24051376 src = 0x1703760 dst = 0x0 The master conntrack of the expectation has no reply tuple. However, the filtering routine needs it. To avoid this issue, emulate the source address in the reply tuple. While at it, fix incorrect sanity checking that should have caught this issue. Thanks to Florian Westphal for initial diagnosing of this bug. Reported-by: Bill Fink <billfink@mindspring.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--Make_global.am2
-rw-r--r--src/ctnl.c31
-rw-r--r--src/filter.c8
3 files changed, 30 insertions, 11 deletions
diff --git a/Make_global.am b/Make_global.am
index 23c7dd0..8084249 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CFLAGS = -std=gnu99 -W -Wall \
- -Wmissing-prototypes -Wwrite-strings -Wcast-qual -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \
+ -Wmissing-prototypes -Wwrite-strings -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \
-Wno-unused-parameter ${LIBNFNETLINK_CFLAGS} ${LIBMNL_CFLAGS} \
${LIBNETFILTER_CONNTRACK_CFLAGS} \
${LIBNETFILTER_CTTIMEOUT_CFLAGS} \
diff --git a/src/ctnl.c b/src/ctnl.c
index bb54727..9e1cfa1 100644
--- a/src/ctnl.c
+++ b/src/ctnl.c
@@ -211,14 +211,35 @@ out:
return NFCT_CB_CONTINUE;
}
+static const struct nf_conntrack *exp_get_master_ct(struct nf_expect *exp)
+{
+ struct nf_conntrack *master =
+ (struct nf_conntrack *)nfexp_get_attr(exp, ATTR_EXP_MASTER);
+
+ /* The function ct_filter_conntrack needs the source address of the
+ * reply tuple, emulate it.
+ */
+ switch (nfct_get_attr_u8(master, ATTR_L3PROTO)) {
+ case AF_INET:
+ nfct_set_attr_u32(master, ATTR_REPL_IPV4_SRC,
+ nfct_get_attr_u32(master, ATTR_IPV4_DST));
+ break;
+ case AF_INET6:
+ nfct_set_attr(master, ATTR_REPL_IPV6_SRC,
+ nfct_get_attr(master, ATTR_IPV6_DST));
+ break;
+ }
+
+ return master;
+}
+
static int exp_event_handler(const struct nlmsghdr *nlh,
enum nf_conntrack_msg_type type,
struct nf_expect *exp,
void *data)
{
int origin_type;
- const struct nf_conntrack *master =
- nfexp_get_attr(exp, ATTR_EXP_MASTER);
+ const struct nf_conntrack *master = exp_get_master_ct(exp);
STATE(stats).nl_events_received++;
@@ -275,8 +296,7 @@ static int dump_handler(enum nf_conntrack_msg_type type,
static int exp_dump_handler(enum nf_conntrack_msg_type type,
struct nf_expect *exp, void *data)
{
- const struct nf_conntrack *master =
- nfexp_get_attr(exp, ATTR_EXP_MASTER);
+ const struct nf_conntrack *master = exp_get_master_ct(exp);
if (!exp_filter_find(STATE(exp_filter), exp))
return NFCT_CB_CONTINUE;
@@ -309,8 +329,7 @@ static int get_handler(enum nf_conntrack_msg_type type,
static int exp_get_handler(enum nf_conntrack_msg_type type,
struct nf_expect *exp, void *data)
{
- const struct nf_conntrack *master =
- nfexp_get_attr(exp, ATTR_EXP_MASTER);
+ const struct nf_conntrack *master = exp_get_master_ct(exp);
if (!exp_filter_find(STATE(exp_filter), exp))
return NFCT_CB_CONTINUE;
diff --git a/src/filter.c b/src/filter.c
index 02a8078..e21cfde 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -373,8 +373,8 @@ static inline int ct_filter_sanity_check(const struct nf_conntrack *ct)
switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) {
case AF_INET:
- if (!nfct_attr_is_set(ct, ATTR_IPV4_SRC) ||
- !nfct_attr_is_set(ct, ATTR_IPV4_DST)) {
+ if (!nfct_attr_is_set(ct, ATTR_ORIG_IPV4_SRC) ||
+ !nfct_attr_is_set(ct, ATTR_REPL_IPV4_SRC)) {
dlog(LOG_ERR, "missing IPv4 address. "
"You forgot to load "
"nf_conntrack_ipv4?");
@@ -382,8 +382,8 @@ static inline int ct_filter_sanity_check(const struct nf_conntrack *ct)
}
break;
case AF_INET6:
- if (!nfct_attr_is_set(ct, ATTR_IPV6_SRC) ||
- !nfct_attr_is_set(ct, ATTR_IPV6_DST)) {
+ if (!nfct_attr_is_set(ct, ATTR_ORIG_IPV6_SRC) ||
+ !nfct_attr_is_set(ct, ATTR_REPL_IPV6_SRC)) {
dlog(LOG_ERR, "missing IPv6 address. "
"You forgot to load "
"nf_conntrack_ipv6?");