Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_conntrack_irc: Tighten matching on DCC message

CTCP messages should only be at the start of an IRC message, not
anywhere within it.

While the helper only decodes packes in the ORIGINAL direction, its
possible to make a client send a CTCP message back by empedding one into
a PING request. As-is, thats enough to make the helper believe that it
saw a CTCP message.

Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port")
Signed-off-by: David Leadbeater <dgl@dgl.cx>
Signed-off-by: Florian Westphal <fw@strlen.de>

authored by

David Leadbeater and committed by
Florian Westphal
e8d5dfd1 25b327d4

+28 -6
+28 -6
net/netfilter/nf_conntrack_irc.c
··· 157 157 data = ib_ptr; 158 158 data_limit = ib_ptr + datalen; 159 159 160 - /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 161 - * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ 162 - while (data < data_limit - (19 + MINMATCHLEN)) { 163 - if (memcmp(data, "\1DCC ", 5)) { 160 + /* Skip any whitespace */ 161 + while (data < data_limit - 10) { 162 + if (*data == ' ' || *data == '\r' || *data == '\n') 163 + data++; 164 + else 165 + break; 166 + } 167 + 168 + /* strlen("PRIVMSG x ")=10 */ 169 + if (data < data_limit - 10) { 170 + if (strncasecmp("PRIVMSG ", data, 8)) 171 + goto out; 172 + data += 8; 173 + } 174 + 175 + /* strlen(" :\1DCC SENT t AAAAAAAA P\1\n")=26 176 + * 7+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=26 177 + */ 178 + while (data < data_limit - (21 + MINMATCHLEN)) { 179 + /* Find first " :", the start of message */ 180 + if (memcmp(data, " :", 2)) { 164 181 data++; 165 182 continue; 166 183 } 184 + data += 2; 185 + 186 + /* then check that place only for the DCC command */ 187 + if (memcmp(data, "\1DCC ", 5)) 188 + goto out; 167 189 data += 5; 168 - /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ 190 + /* we have at least (21+MINMATCHLEN)-(2+5) bytes valid data left */ 169 191 170 192 iph = ip_hdr(skb); 171 193 pr_debug("DCC found in master %pI4:%u %pI4:%u\n", ··· 203 181 pr_debug("DCC %s detected\n", dccprotos[i]); 204 182 205 183 /* we have at least 206 - * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid 184 + * (21+MINMATCHLEN)-7-dccprotos[i].matchlen bytes valid 207 185 * data left (== 14/13 bytes) */ 208 186 if (parse_dcc(data, data_limit, &dcc_ip, 209 187 &dcc_port, &addr_beg_p, &addr_end_p)) {