|
Bugzilla – Full Text Bug Listing |
| Summary: | VUL-0: CVE-2004-0816: kernel: ipt_log ICMP remote DoS in kernel 2.6 / CAN-2004-0816 | ||
|---|---|---|---|
| Product: | [Novell Products] SUSE Security Incidents | Reporter: | Ludwig Nussel <lnussel> |
| Component: | Incidents | Assignee: | Marcus Meissner <meissner> |
| Status: | RESOLVED FIXED | QA Contact: | Security Team bot <security-team> |
| Severity: | Critical | ||
| Priority: | P3 - Medium | CC: | meissner, rf, security-team |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | CVE-2004-0816: CVSS v2 Base Score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P) | ||
| Found By: | --- | Services Priority: | |
| Business Priority: | Blocker: | --- | |
| Marketing QA Status: | --- | IT Deployment: | --- |
| Attachments: |
original report with sample code?
oops.jpg oops2.jpg Proposed patch Updated patch |
||
|
Description
Ludwig Nussel
2004-09-24 18:00:33 UTC
Created attachment 23931 [details]
original report with sample code?
This program just sends a single stand ICMP unreachable for a TCP connection. It's hard to imagine it should cause any problems. TCP should even reject it most of the time because it has a fixed sequence number and TCP only allows icmps which fit the current window. no, this guy is right. with SuSEfirwall2 enabled the kernel crashes. I was able to get a panic on x86_64. Unfortunately the serial console doesn't work for some reason on this host (laptop). The backtrace was ipt_LOG and then memcpy. On a i386 laptop the machine instantly rebootes or locks up without panic when using the nuke program. steps to reproduce: # cp /var/adm/fillup-templates/sysconfig.SuSEfirewall2 /etc/sysconfig/SuSEfirewall2 # SuSEfirewall2 then nuke the host Ok, then ipt_LOG is buggy. That's possible. Please log the oops somehow and I can look into it. Unfortunately the serial device does not seem to work at all and netconsole doesn't work either so I have to type it by hand: __memcpy+11 skb_copy_bits+91 :ipt_LOG:dump_packet+1052 Created attachment 23938 [details]
oops.jpg
(on amd64 laptop)
FWIW, I ran the exploit against a 2.6.8 kernel on x86_64, and no crash occurred. Do you have the beginning of the oops too? The new subject is wrong, this isn't ipt6_LOG, but ipt_LOG I see divide error 0000 [1] Created attachment 23940 [details]
oops2.jpg
full oops
FWIW, the simplest way to reproduce is this: hammer:~ # echo 1 > /proc/sys/kernel/sysrq hammer:~ # klogconsole -r0 -l8 hammer:~ # iptables -A INPUT -j LOG --log-level warning \ --log-tcp-options --log-ip-options -p icmp and running the exploit against the victim host Stupid old thinko - we've had the same sort of problems in other areas
of netfilter before
optsize = tcph.doff * 4 - sizeof(struct tcphdr);
if (skb_copy_bits(skb, iphoff+iph.ihl*4 + sizeof(tcph),
opt, optsize) < 0) {
printk("TRUNCATED");
return;
}
... and optsize goes negative if tcph.doff is 0.
Created attachment 23941 [details]
Proposed patch
Proposed patch. ip6t_LOG had the same problem.
In 2.6.8, ipt_LOG is unaffected because it checks that
4 * doff > sizeof(tcphdr). The 2.6.8 ip6t_LOG module has this
bug though.
No, that's not it. There is a if before it
if ((info->logflags & IPT_LOG_TCPOPT)
&& th->doff * 4 > sizeof(struct tcphdr)) {
But the crash was in ipt_LOG (for lnussel's description, Marcus' version doesn't make much sense) And the test case also sends ipv4, not ipv6. ... fixed summary line... Andi: yes, but in our 2.6.5 kernel the if() line reads like this:
if ((info->logflags & IP6T_LOG_TCPOPT)
&& tcph->doff * 4 != sizeof(struct tcphdr)) {
Note the !=, not >. That was changed some time between 2.6.5 and 2.6.8.
And that's why 2.6.5 crashes, and 2.6.8 doesn't.
And of course the crash is in ipt_LOG. I didn't say it wasn't. All I'm saying
is that the same sort of attack would be successful against ip6t_LOG as well.
Ah right I looked in the wrong kernel source. BTW the ip options printing in SLES9SP1 has the same bug
if ((info->logflags & IPT_LOG_IPOPT)
&& iph.ihl * 4 != sizeof(struct iphdr)) {
unsigned char opt[4 * 15 - sizeof(struct iphdr)];
unsigned int i, optsize;
optsize = iph.ihl * 4 - sizeof(struct iphdr);
if (skb_copy_bits(skb, iphoff+sizeof(iph), opt, optsize) < 0) {
printk("TRUNCATED");
return;
}
But I don't think it's exploitable because those short packets will
be rejected very early, probably before any netfilter hooks
please use a "safe" approach in the ip6t case, aka check for the size if you are unsure. better safe than sorry. Andi: possibly exploitable if you build something like sane IP header ICMP port unreach broken IP header Marcus: I don't understand your comment. What do you mean by safe approach? Do you see any problem with my patch? Olaf, true. I would suggest a full careful audit of ipt_LOG, there may be more dragons there. Scary that firewall code has so bad code quality ... Marcus - can someone from your team do this audit, please? It may be a good idea to diff 2.6.5 against 2.6.8 and see which changes may have been security relevant. It looks as if this issue was fixed quietly by DaveM or Linus. It may also be a good idea to inform vendor-sec. I wonder how long this exploit has been circulating already... somehow it doesn't feel as if the reporter is the author of the exploit. Created attachment 23949 [details]
Updated patch
This patch adds a check for bad iph.ihl
These bugs are present in SLES8 as well. Hooray... Hmm, we have a SLES8 update kernel in the queue. If this is already public and we do want to fix it as soon as possible, it might be an option to stop its release. OTOH, I understood there will be another security update soon anyway, so we can as well roll it in there. The current sles8 kernel update will not be touched anymore. We will roll it into the next one, which will be coming anyway. I committed the patch to SLES8 HEAD, SLES9 SP1 and GA branches, and verified that the exploit is no longer effective against a patched kernel. kernel-source-26 HEAD remains unpatched for now until Marcus tells me to go ahead. So it looks like we already have a first candidate for a kernel security update after releasing 9.2 :) I'm assigning this to security-team for further tracking. Re: Kurt's comment - I don't think this is public yet. The kernel maintainers fixed it quietly. Theres similar code in ip_tables.c (2.6.0 checked):
static int
tcp_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
int *hotdrop)
{
...
if (tcpinfo->option &&
!tcp_find_option(tcpinfo->option, skb, tcph.doff*4 - sizeof(tcph),
tcpinfo->invflags & IPT_TCP_INV_OPTION,
hotdrop))
...
}
Seems the tcp header isnt validated before.
That is old news - I found this bug in June or so, and it's been fixed in
mainline for a while. 2.6.8 current has this:
if (th->doff * 4 < sizeof(_tcph)) {
*hotdrop = 1;
return 0;
}
if (!tcp_find_option(tcpinfo->option, skb,
th->doff*4 - sizeof(_tcph),
tcpinfo->invflags & IPT_TCP_INV_OPTION,
hotdrop))
return 0;
Please make sure you look at the current Suse kernel source code. 2.6.0
is definitely way outdated.
CAN-2004-0816 The important parts of the patch were in 2.6.8, vendor-sec considers this issue public. Only 9.1 and SLES 9 kernels are affected. (2.4 kernels are not affected.) comment#26 states 2.4 kernels (SLES8) are affected. We have verified that it does not affect 2.4 kernels. kernels and advisories released. CVE-2004-0816: CVSS v2 Base Score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P) |