diff mbox

cls_u32: use skb_copy_bits() to dereference data safely

Message ID 1275481538.14363.10.camel@bigi
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

jamal June 2, 2010, 12:25 p.m. UTC
On Wed, 2010-06-02 at 08:21 -0400, jamal wrote:

> Can we make the fix very simple please? i.e no copy bits, this is the
> fast path.

Example, something along lines of:

---
----


cheers,
jamal

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

David Miller June 2, 2010, 12:45 p.m. UTC | #1
From: jamal <hadi@cyberus.ca>
Date: Wed, 02 Jun 2010 08:25:38 -0400

> --- a/net/sched/cls_u32.c
> +++ b/net/sched/cls_u32.c
> @@ -135,6 +135,9 @@ next_knode:
>  
>  for (i = n->sel.nkeys; i>0; i--, key++) {
>  
> +        int toff = key->off+(off2&key->offmask)- 4;
> +        if (unlikely(toff > skb->len))
> +              /* bailout here - needs some thought */
>          if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->v

I don't think it's that simple.

You can't dereference from the skb->data linear area if your offset is
beyond "skb->len - skb->data_len" (aka. skb_headlen()) since that's
where the paged or fragmented portion starts.

We really need to use skb_copy_bits() if we want to allow
any offset into the SKB, and because of all the ways
packets can be transformed and constructed we absolutely
have to.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Changli Gao June 2, 2010, 1:14 p.m. UTC | #2
On Wed, Jun 2, 2010 at 8:45 PM, David Miller <davem@davemloft.net> wrote:
> From: jamal <hadi@cyberus.ca>
> Date: Wed, 02 Jun 2010 08:25:38 -0400
>
>> --- a/net/sched/cls_u32.c
>> +++ b/net/sched/cls_u32.c
>> @@ -135,6 +135,9 @@ next_knode:
>>
>>  for (i = n->sel.nkeys; i>0; i--, key++) {
>>
>> +        int toff = key->off+(off2&key->offmask)- 4;
>> +        if (unlikely(toff > skb->len))
>> +              /* bailout here - needs some thought */
>>          if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->v
>
> I don't think it's that simple.
>
> You can't dereference from the skb->data linear area if your offset is
> beyond "skb->len - skb->data_len" (aka. skb_headlen()) since that's
> where the paged or fragmented portion starts.
>
> We really need to use skb_copy_bits() if we want to allow
> any offset into the SKB, and because of all the ways
> packets can be transformed and constructed we absolutely
> have to.
>

Maybe skb_header_pointer() is lighter.
David Miller June 2, 2010, 1:27 p.m. UTC | #3
From: Changli Gao <xiaosuo@gmail.com>
Date: Wed, 2 Jun 2010 21:14:55 +0800

> On Wed, Jun 2, 2010 at 8:45 PM, David Miller <davem@davemloft.net> wrote:
>> From: jamal <hadi@cyberus.ca>
>> Date: Wed, 02 Jun 2010 08:25:38 -0400
>>
>>> --- a/net/sched/cls_u32.c
>>> +++ b/net/sched/cls_u32.c
>>> @@ -135,6 +135,9 @@ next_knode:
>>>
>>>  for (i = n->sel.nkeys; i>0; i--, key++) {
>>>
>>> +        int toff = key->off+(off2&key->offmask)- 4;
>>> +        if (unlikely(toff > skb->len))
>>> +              /* bailout here - needs some thought */
>>>          if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->v
>>
>> I don't think it's that simple.
>>
>> You can't dereference from the skb->data linear area if your offset is
>> beyond "skb->len - skb->data_len" (aka. skb_headlen()) since that's
>> where the paged or fragmented portion starts.
>>
>> We really need to use skb_copy_bits() if we want to allow
>> any offset into the SKB, and because of all the ways
>> packets can be transformed and constructed we absolutely
>> have to.
>>
> 
> Maybe skb_header_pointer() is lighter.

Yes, it should be.  In fact, it's designed for this kind of situation
and that's why it's used extensively in netfilter.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
jamal June 2, 2010, 1:36 p.m. UTC | #4
On Wed, 2010-06-02 at 21:14 +0800, Changli Gao wrote:


> Maybe skb_header_pointer() is lighter.

A little worse than skb_copy_bits(). In any case, this change is going
to hurt.
Dave, can we assume the upper layers(qdiscs in this case) are
responsible for any linearizing?

Changli, if you have time - can you also audit tcf_pedit()
since it follows TheLinuxWay(tm).

cheers,
jamal

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Changli Gao June 2, 2010, 1:43 p.m. UTC | #5
On Wed, Jun 2, 2010 at 9:36 PM, jamal <hadi@cyberus.ca> wrote:
> On Wed, 2010-06-02 at 21:14 +0800, Changli Gao wrote:
>
>
>> Maybe skb_header_pointer() is lighter.
>
> A little worse than skb_copy_bits(). In any case, this change is going
> to hurt.

Why? it is an inline function, and in most cases, there isn't any function call.

> Dave, can we assume the upper layers(qdiscs in this case) are
> responsible for any linearizing?
>
> Changli, if you have time - can you also audit tcf_pedit()
> since it follows TheLinuxWay(tm).
>

Yea, pedit has the same issue. Besides this issue, they should use
get_unaligned() instead.
David Miller June 2, 2010, 1:43 p.m. UTC | #6
From: jamal <hadi@cyberus.ca>
Date: Wed, 02 Jun 2010 09:36:37 -0400

> On Wed, 2010-06-02 at 21:14 +0800, Changli Gao wrote:
> 
> 
>> Maybe skb_header_pointer() is lighter.
> 
> A little worse than skb_copy_bits(). In any case, this change is going
> to hurt.

Umm, Jamal what are you talking about?

Using skb_header_pointer(), if the offset is in range, there is no
change from today other than a comparison.

If it is not in range, we use skb_copy_bits().  It's only for the
case where we have to fetch the value from the fragmented part
of the SKB.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
jamal June 2, 2010, 1:47 p.m. UTC | #7
On Wed, 2010-06-02 at 06:43 -0700, David Miller wrote:
> From: jamal <hadi@cyberus.ca>

> > 
> > A little worse than skb_copy_bits(). In any case, this change is going
> > to hurt.
> 
> Umm, Jamal what are you talking about?

;->

> Using skb_header_pointer(), if the offset is in range, there is no
> change from today other than a comparison.

Thats the part i glossed over - My eyes just saw "it calls
skb_copy_bits()" ;->

> If it is not in range, we use skb_copy_bits().  It's only for the
> case where we have to fetch the value from the fragmented part
> of the SKB.

cheers,
jamal

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
jamal June 2, 2010, 1:48 p.m. UTC | #8
On Wed, 2010-06-02 at 21:43 +0800, Changli Gao wrote:

> Yea, pedit has the same issue. Besides this issue, they should use
> get_unaligned() instead.

sounds reasonable - although they are probably different patches with
the offset fix being more important.

cheers,
jamal

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 9627542..dde7a23 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -135,6 +135,9 @@  next_knode:
 
 for (i = n->sel.nkeys; i>0; i--, key++) {
 
+        int toff = key->off+(off2&key->offmask)- 4;
+        if (unlikely(toff > skb->len))
+              /* bailout here - needs some thought */
         if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->v
             n = n->next;
             goto next_knode;