Hi,
it appears that bad filters in net/core/filter.c can read/write arbitrary
kernel memory.
Given a filter created via:
struct sock_filter s[2];
memset(s, 0, sizeof s);
s[0].code = BPF_LD|BPF_B|BPF_ABS;
s[0].k = 0x7fffffffUL;
s[1].code = BPF_RET;
s[1].k = 0xfffffff0UL;
or:
s[0].code = BPF_LD|BPF_B|BPF_IND;
s[0].k = 0x7fffffffUL;
s[1].code = BPF_RET;
s[1].k = 0xfffffff0UL;
or
s[0].code = BPF_LD|BPF_H|BPF_IND;
s[0].k = 0x7ffffffeUL;
s[1].code = BPF_B|BPF_RET;
s[1].k = 0xfffffff0UL;
or
s[0].code = BPF_LD|BPF_H|BPF_IND;
s[0].k = 0x7ffffffeUL;
s[1].code = BPF_B|BPF_RET;
s[1].k = 0xfffffff0UL;
These pass check filter calls:
sk_chk_filter(s, 2)
But then blow up severely after calling:
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer)
{
int hlen = skb_headlen(skb);
which increments the data pointer:
if (offset + len <= hlen)
return skb->data + offset;
but does not check if (offset+len) could overflow.
Something gross along the lines of:
if((offset + len) < offset) {
printf("ERROR: hit overflow!\n");
return NULL;
}
seems to fix the problem, but most likely filter.c should do it.
If anyone could confirm or refute these I'd appreciate it. [We've been
developing a tool to automatically generate test cases by running code
partially symbolically and these were some of first errors it flagged.]
Dawson
Dawson Engler <[email protected]> wrote:
>
> But then blow up severely after calling:
>
> static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
> int len, void *buffer)
> {
> int hlen = skb_headlen(skb);
>
>
> which increments the data pointer:
>
> if (offset + len <= hlen)
> return skb->data + offset;
This check was fixed 3 months ago with the changeset:
55820ee2f8c767a2833b21bd365e5753f50bd8ce
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt