summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2010-09-03 12:07:54 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2010-09-08 10:50:19 +0200
commit3e36a3507d03c02b11a94c7e6691efc2a2b9253f (patch)
treef5dad3fc21645122a7f496562b442f849818e149
parent6e18d454004fcaff4b6064c04989db51393395e7 (diff)
ct: fix EINVAL if not TCP attributes are set for Linux kernel <= 2.6.25
This patch fixes an EINVAL error that we hit in Linux kernel <= 2.6.25. Basically, if we send an empty CTA_PROTOINFO_TCP attribute nest, the kernel returns EINVAL. To fix this, we previously check if there is any TCP attribute set. Reported-by: Rui Sousa <rui.sousa@mindspeed.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--src/conntrack/build.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/src/conntrack/build.c b/src/conntrack/build.c
index b878ddd..ec7623d 100644
--- a/src/conntrack/build.c
+++ b/src/conntrack/build.c
@@ -106,6 +106,18 @@ static void __build_protoinfo(struct nfnlhdr *req, size_t size,
switch(ct->tuple[__DIR_ORIG].protonum) {
case IPPROTO_TCP:
+ /* Preliminary attribute check to avoid sending an empty
+ * CTA_PROTOINFO_TCP nest, which results in EINVAL in
+ * Linux kernel <= 2.6.25. */
+ if (!(test_bit(ATTR_TCP_STATE, ct->set) ||
+ test_bit(ATTR_TCP_FLAGS_ORIG, ct->set) ||
+ test_bit(ATTR_TCP_FLAGS_REPL, ct->set) ||
+ test_bit(ATTR_TCP_MASK_ORIG, ct->set) ||
+ test_bit(ATTR_TCP_MASK_REPL, ct->set) ||
+ test_bit(ATTR_TCP_WSCALE_ORIG, ct->set) ||
+ test_bit(ATTR_TCP_WSCALE_REPL, ct->set))) {
+ break;
+ }
nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP);
if (test_bit(ATTR_TCP_STATE, ct->set))
@@ -139,6 +151,12 @@ static void __build_protoinfo(struct nfnlhdr *req, size_t size,
nfnl_nest_end(&req->nlh, nest);
break;
case IPPROTO_SCTP:
+ /* See comment above on TCP. */
+ if (!(test_bit(ATTR_SCTP_STATE, ct->set) ||
+ test_bit(ATTR_SCTP_VTAG_ORIG, ct->set) ||
+ test_bit(ATTR_SCTP_VTAG_REPL, ct->set))) {
+ break;
+ }
nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_SCTP);
if (test_bit(ATTR_SCTP_STATE, ct->set))
@@ -158,6 +176,12 @@ static void __build_protoinfo(struct nfnlhdr *req, size_t size,
nfnl_nest_end(&req->nlh, nest);
break;
case IPPROTO_DCCP:
+ /* See comment above on TCP. */
+ if (!(test_bit(ATTR_DCCP_STATE, ct->set) ||
+ test_bit(ATTR_DCCP_ROLE, ct->set) ||
+ test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->set))) {
+ break;
+ }
nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_DCCP);
if (test_bit(ATTR_DCCP_STATE, ct->set))