As I promised in my previous post, here is an official public disclosure of CVE 2016-8633: linux kernel firewire driver remote code execution. The official fix was merged yesterday into the linux kernel, and so I can know talk freely about it.
In the middle of October I downloaded the latest (4.8) linux kernel version, and started to search for a potential driver vulnerability. I soon stumbled upon the firewire driver, and decided to check it out, a decision that quickly paid off. The driver supports IPv4 over IEEE 1394, meaning that IPv4 networking can be established over the firewire cable. As is very common in such network interfaces, the driver supports fragmentation, a high risk feature that was responsible to 2/3 of the previous disclosed CVEs.
Here is a snippet of the driver’s code when handling the first fragment (/drivers/firewire/net.c) :
new->datagram_label = datagram_label; new->datagram_size = dg_size; new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net)); if (new->skb == NULL) goto fail_w_fi; skb_reserve(new->skb, LL_RESERVED_SPACE(net)); new->pbuf = skb_put(new->skb, dg_size); // EI-Vuln : classic bof in a single fragment: // EI : dg_size (3 nibbles) = size of new->pbuf (+LL_RESERVED_SPACE) : 10 // EI : frag_off (3 nibbles) ==> can be bigger than dg_size : 4024 // EI : frag_len (network length) ==> no checks at all on it : 1024 // EI : A clear and simple buffer overflow on alloc metadata memcpy(new->pbuf + frag_off, frag_buf, frag_len);
Although the driver supports fragments reordering, i.e. fragments that arrive out-of-order, and even uses a metadata list to keep track over the “holes” in the overall buffer, it seems that the basic checks are missing:
- There is no check that the over all message size (dg_size) is sane
- There is no check that the offset (frag_off) is bound by the overall size
- There is no check that the overall size is bigger than the current fragment (frag_len)
Using all of these together, we can easily achieve the most awarding fragmentation exploit: buffer overflow in a single fragment. As mentioned in my code comment, by using a small dg_size together with controlled (and largre) frag_off and frag_len, an attacker will be able to store his fragment over important metadata, with a wide range of overflow options. This attack can result in a remote code execution across the firewire cable.
This vulnerability dates back to 2009, since the driver was first introduced into the linux kernel. It is worth mentioning that due to the elegant “holes” managing using the metadata list, the only needed fix was to verify the 3 parameters using a single if-check. In addition, the time passed since my report was sent and a fix was written and integrated was very quick, when compared to other projects, and this is remarkable.
As mentioned in the previous post, and will be discussed in details in a future post that will focus on the risks of fragmentation, fragmentation is a high-risk feature. It is very hard to implement it safely, and this 7 years old vulnerability is yet another proof for the dangers it can pose to networking code.