diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2010-09-03 12:07:54 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2010-09-08 10:50:19 +0200 |
commit | 3e36a3507d03c02b11a94c7e6691efc2a2b9253f (patch) | |
tree | f5dad3fc21645122a7f496562b442f849818e149 /src/conntrack | |
parent | 6e18d454004fcaff4b6064c04989db51393395e7 (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>
Diffstat (limited to 'src/conntrack')
-rw-r--r-- | src/conntrack/build.c | 24 |
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)) |