From 3e36a3507d03c02b11a94c7e6691efc2a2b9253f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 3 Sep 2010 12:07:54 +0200 Subject: 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 Signed-off-by: Pablo Neira Ayuso --- src/conntrack/build.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) 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)) -- cgit v1.2.3