netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq
@ 2020-03-04  8:51 Xin Long
  2020-03-09  9:15 ` Steffen Klassert
  2020-03-09 10:07 ` Mika Penttilä
  0 siblings, 2 replies; 5+ messages in thread
From: Xin Long @ 2020-03-04  8:51 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Herbert Xu, David S. Miller, Sabrina Dubroca

Xiumei found a panic in esp offload:

  BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
  RIP: 0010:esp_output_done+0x101/0x160 [esp4]
  Call Trace:
   ? esp_output+0x180/0x180 [esp4]
   cryptd_aead_crypt+0x4c/0x90
   cryptd_queue_worker+0x6e/0xa0
   process_one_work+0x1a7/0x3b0
   worker_thread+0x30/0x390
   ? create_worker+0x1a0/0x1a0
   kthread+0x112/0x130
   ? kthread_flush_work_fn+0x10/0x10
   ret_from_fork+0x35/0x40

It was caused by that skb secpath is used in esp_output_done() after it's
been released elsewhere.

The tx path for esp offload is:

  __dev_queue_xmit()->
    validate_xmit_skb_list()->
      validate_xmit_xfrm()->
        esp_xmit()->
          esp_output_tail()->
            aead_request_set_callback(esp_output_done) <--[1]
            crypto_aead_encrypt()  <--[2]

In [1], .callback is set, and in [2] it will trigger the worker schedule,
later on a kernel thread will call .callback(esp_output_done), as the call
trace shows.

But in validate_xmit_xfrm():

  skb_list_walk_safe(skb, skb2, nskb) {
    ...
    err = x->type_offload->xmit(x, skb2, esp_features);  [esp_xmit]
    ...
  }

When the err is -EINPROGRESS, which means this skb2 will be enqueued and
later gets encrypted and sent out by .callback later in a kernel thread,
skb2 should be removed fromt skb chain. Otherwise, it will get processed
again outside validate_xmit_xfrm(), which could release skb secpath, and
cause the panic above.

This patch is to remove the skb from the chain when it's enqueued in
cryptd_wq. While at it, remove the unnecessary 'if (!skb)' check.

Fixes: 3dca3f38cfb8 ("xfrm: Separate ESP handling from segmentation for GRO packets.")
Reported-by: Xiumei Mu <xmu@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 net/xfrm/xfrm_device.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 3231ec6..e2db468 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -78,8 +78,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
 	int err;
 	unsigned long flags;
 	struct xfrm_state *x;
-	struct sk_buff *skb2, *nskb;
 	struct softnet_data *sd;
+	struct sk_buff *skb2, *nskb, *pskb = NULL;
 	netdev_features_t esp_features = features;
 	struct xfrm_offload *xo = xfrm_offload(skb);
 	struct sec_path *sp;
@@ -168,14 +168,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
 		} else {
 			if (skb == skb2)
 				skb = nskb;
-
-			if (!skb)
-				return NULL;
+			else
+				pskb->next = nskb;
 
 			continue;
 		}
 
 		skb_push(skb2, skb2->data - skb_mac_header(skb2));
+		pskb = skb2;
 	}
 
 	return skb;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq
  2020-03-04  8:51 [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq Xin Long
@ 2020-03-09  9:15 ` Steffen Klassert
  2020-03-09 10:07 ` Mika Penttilä
  1 sibling, 0 replies; 5+ messages in thread
From: Steffen Klassert @ 2020-03-09  9:15 UTC (permalink / raw)
  To: Xin Long; +Cc: netdev, Herbert Xu, David S. Miller, Sabrina Dubroca

On Wed, Mar 04, 2020 at 04:51:42PM +0800, Xin Long wrote:
> Xiumei found a panic in esp offload:
> 
>   BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
>   RIP: 0010:esp_output_done+0x101/0x160 [esp4]
>   Call Trace:
>    ? esp_output+0x180/0x180 [esp4]
>    cryptd_aead_crypt+0x4c/0x90
>    cryptd_queue_worker+0x6e/0xa0
>    process_one_work+0x1a7/0x3b0
>    worker_thread+0x30/0x390
>    ? create_worker+0x1a0/0x1a0
>    kthread+0x112/0x130
>    ? kthread_flush_work_fn+0x10/0x10
>    ret_from_fork+0x35/0x40
> 
> It was caused by that skb secpath is used in esp_output_done() after it's
> been released elsewhere.
> 
> The tx path for esp offload is:
> 
>   __dev_queue_xmit()->
>     validate_xmit_skb_list()->
>       validate_xmit_xfrm()->
>         esp_xmit()->
>           esp_output_tail()->
>             aead_request_set_callback(esp_output_done) <--[1]
>             crypto_aead_encrypt()  <--[2]
> 
> In [1], .callback is set, and in [2] it will trigger the worker schedule,
> later on a kernel thread will call .callback(esp_output_done), as the call
> trace shows.
> 
> But in validate_xmit_xfrm():
> 
>   skb_list_walk_safe(skb, skb2, nskb) {
>     ...
>     err = x->type_offload->xmit(x, skb2, esp_features);  [esp_xmit]
>     ...
>   }
> 
> When the err is -EINPROGRESS, which means this skb2 will be enqueued and
> later gets encrypted and sent out by .callback later in a kernel thread,
> skb2 should be removed fromt skb chain. Otherwise, it will get processed
> again outside validate_xmit_xfrm(), which could release skb secpath, and
> cause the panic above.
> 
> This patch is to remove the skb from the chain when it's enqueued in
> cryptd_wq. While at it, remove the unnecessary 'if (!skb)' check.
> 
> Fixes: 3dca3f38cfb8 ("xfrm: Separate ESP handling from segmentation for GRO packets.")
> Reported-by: Xiumei Mu <xmu@redhat.com>
> Signed-off-by: Xin Long <lucien.xin@gmail.com>

Applied, thanks a lot Xin!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq
  2020-03-04  8:51 [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq Xin Long
  2020-03-09  9:15 ` Steffen Klassert
@ 2020-03-09 10:07 ` Mika Penttilä
  2020-03-09 10:50   ` Xin Long
  1 sibling, 1 reply; 5+ messages in thread
From: Mika Penttilä @ 2020-03-09 10:07 UTC (permalink / raw)
  To: Xin Long, netdev
  Cc: Steffen Klassert, Herbert Xu, David S. Miller, Sabrina Dubroca

[-- Attachment #1: Type: text/plain, Size: 3062 bytes --]


Hi!

On 4.3.2020 10.51, Xin Long wrote:
> Xiumei found a panic in esp offload:
>
>   BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
>   RIP: 0010:esp_output_done+0x101/0x160 [esp4]
>   Call Trace:
>    ? esp_output+0x180/0x180 [esp4]
>    cryptd_aead_crypt+0x4c/0x90
>    cryptd_queue_worker+0x6e/0xa0
>    process_one_work+0x1a7/0x3b0
>    worker_thread+0x30/0x390
>    ? create_worker+0x1a0/0x1a0
>    kthread+0x112/0x130
>    ? kthread_flush_work_fn+0x10/0x10
>    ret_from_fork+0x35/0x40
>
> It was caused by that skb secpath is used in esp_output_done() after it's
> been released elsewhere.
>
> The tx path for esp offload is:
>
>   __dev_queue_xmit()->
>     validate_xmit_skb_list()->
>       validate_xmit_xfrm()->
>         esp_xmit()->
>           esp_output_tail()->
>             aead_request_set_callback(esp_output_done) <--[1]
>             crypto_aead_encrypt()  <--[2]
>
> In [1], .callback is set, and in [2] it will trigger the worker schedule,
> later on a kernel thread will call .callback(esp_output_done), as the call
> trace shows.
>
> But in validate_xmit_xfrm():
>
>   skb_list_walk_safe(skb, skb2, nskb) {
>     ...
>     err = x->type_offload->xmit(x, skb2, esp_features);  [esp_xmit]
>     ...
>   }
>
> When the err is -EINPROGRESS, which means this skb2 will be enqueued and
> later gets encrypted and sent out by .callback later in a kernel thread,
> skb2 should be removed fromt skb chain. Otherwise, it will get processed
> again outside validate_xmit_xfrm(), which could release skb secpath, and
> cause the panic above.
>
> This patch is to remove the skb from the chain when it's enqueued in
> cryptd_wq. While at it, remove the unnecessary 'if (!skb)' check.
>
> Fixes: 3dca3f38cfb8 ("xfrm: Separate ESP handling from segmentation for GRO packets.")
> Reported-by: Xiumei Mu <xmu@redhat.com>
> Signed-off-by: Xin Long <lucien.xin@gmail.com>
> ---
>  net/xfrm/xfrm_device.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
> index 3231ec6..e2db468 100644
> --- a/net/xfrm/xfrm_device.c
> +++ b/net/xfrm/xfrm_device.c
> @@ -78,8 +78,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
>  	int err;
>  	unsigned long flags;
>  	struct xfrm_state *x;
> -	struct sk_buff *skb2, *nskb;
>  	struct softnet_data *sd;
> +	struct sk_buff *skb2, *nskb, *pskb = NULL;
>  	netdev_features_t esp_features = features;
>  	struct xfrm_offload *xo = xfrm_offload(skb);
>  	struct sec_path *sp;
> @@ -168,14 +168,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
>  		} else {
>  			if (skb == skb2)
>  				skb = nskb;
> -
> -			if (!skb)
> -				return NULL;
> +			else
> +				pskb->next = nskb;

pskb can be NULL on the first round?



>  			continue;
>  		}
>  
>  		skb_push(skb2, skb2->data - skb_mac_header(skb2));
> +		pskb = skb2;
>  	}
>  
>  	return skb;


[-- Attachment #2: pEpkey.asc --]
[-- Type: application/pgp-keys, Size: 3157 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq
  2020-03-09 10:07 ` Mika Penttilä
@ 2020-03-09 10:50   ` Xin Long
  2020-03-09 11:06     ` Mika Penttilä
  0 siblings, 1 reply; 5+ messages in thread
From: Xin Long @ 2020-03-09 10:50 UTC (permalink / raw)
  To: Mika Penttilä
  Cc: network dev, Steffen Klassert, Herbert Xu, David S. Miller,
	Sabrina Dubroca

On Mon, Mar 9, 2020 at 6:07 PM Mika Penttilä <mika.penttila@nextfour.com> wrote:
>
>
> Hi!
>
> On 4.3.2020 10.51, Xin Long wrote:
> > Xiumei found a panic in esp offload:
> >
> >   BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
> >   RIP: 0010:esp_output_done+0x101/0x160 [esp4]
> >   Call Trace:
> >    ? esp_output+0x180/0x180 [esp4]
> >    cryptd_aead_crypt+0x4c/0x90
> >    cryptd_queue_worker+0x6e/0xa0
> >    process_one_work+0x1a7/0x3b0
> >    worker_thread+0x30/0x390
> >    ? create_worker+0x1a0/0x1a0
> >    kthread+0x112/0x130
> >    ? kthread_flush_work_fn+0x10/0x10
> >    ret_from_fork+0x35/0x40
> >
> > It was caused by that skb secpath is used in esp_output_done() after it's
> > been released elsewhere.
> >
> > The tx path for esp offload is:
> >
> >   __dev_queue_xmit()->
> >     validate_xmit_skb_list()->
> >       validate_xmit_xfrm()->
> >         esp_xmit()->
> >           esp_output_tail()->
> >             aead_request_set_callback(esp_output_done) <--[1]
> >             crypto_aead_encrypt()  <--[2]
> >
> > In [1], .callback is set, and in [2] it will trigger the worker schedule,
> > later on a kernel thread will call .callback(esp_output_done), as the call
> > trace shows.
> >
> > But in validate_xmit_xfrm():
> >
> >   skb_list_walk_safe(skb, skb2, nskb) {
> >     ...
> >     err = x->type_offload->xmit(x, skb2, esp_features);  [esp_xmit]
> >     ...
> >   }
> >
> > When the err is -EINPROGRESS, which means this skb2 will be enqueued and
> > later gets encrypted and sent out by .callback later in a kernel thread,
> > skb2 should be removed fromt skb chain. Otherwise, it will get processed
> > again outside validate_xmit_xfrm(), which could release skb secpath, and
> > cause the panic above.
> >
> > This patch is to remove the skb from the chain when it's enqueued in
> > cryptd_wq. While at it, remove the unnecessary 'if (!skb)' check.
> >
> > Fixes: 3dca3f38cfb8 ("xfrm: Separate ESP handling from segmentation for GRO packets.")
> > Reported-by: Xiumei Mu <xmu@redhat.com>
> > Signed-off-by: Xin Long <lucien.xin@gmail.com>
> > ---
> >  net/xfrm/xfrm_device.c | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> >
> > diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
> > index 3231ec6..e2db468 100644
> > --- a/net/xfrm/xfrm_device.c
> > +++ b/net/xfrm/xfrm_device.c
> > @@ -78,8 +78,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
> >       int err;
> >       unsigned long flags;
> >       struct xfrm_state *x;
> > -     struct sk_buff *skb2, *nskb;
> >       struct softnet_data *sd;
> > +     struct sk_buff *skb2, *nskb, *pskb = NULL;
> >       netdev_features_t esp_features = features;
> >       struct xfrm_offload *xo = xfrm_offload(skb);
> >       struct sec_path *sp;
> > @@ -168,14 +168,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
> >               } else {
> >                       if (skb == skb2)
> >                               skb = nskb;
> > -
> > -                     if (!skb)
> > -                             return NULL;
> > +                     else
> > +                             pskb->next = nskb;
>
> pskb can be NULL on the first round?
On the 1st round, skb == skb2.

>
>
>
> >                       continue;
> >               }
> >
> >               skb_push(skb2, skb2->data - skb_mac_header(skb2));
> > +             pskb = skb2;
> >       }
> >
> >       return skb;
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq
  2020-03-09 10:50   ` Xin Long
@ 2020-03-09 11:06     ` Mika Penttilä
  0 siblings, 0 replies; 5+ messages in thread
From: Mika Penttilä @ 2020-03-09 11:06 UTC (permalink / raw)
  To: Xin Long
  Cc: network dev, Steffen Klassert, Herbert Xu, David S. Miller,
	Sabrina Dubroca

[-- Attachment #1: Type: text/plain, Size: 3683 bytes --]



On 9.3.2020 12.50, Xin Long wrote:
> On Mon, Mar 9, 2020 at 6:07 PM Mika Penttilä <mika.penttila@nextfour.com> wrote:
>>
>> Hi!
>>
>> On 4.3.2020 10.51, Xin Long wrote:
>>> Xiumei found a panic in esp offload:
>>>
>>>   BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
>>>   RIP: 0010:esp_output_done+0x101/0x160 [esp4]
>>>   Call Trace:
>>>    ? esp_output+0x180/0x180 [esp4]
>>>    cryptd_aead_crypt+0x4c/0x90
>>>    cryptd_queue_worker+0x6e/0xa0
>>>    process_one_work+0x1a7/0x3b0
>>>    worker_thread+0x30/0x390
>>>    ? create_worker+0x1a0/0x1a0
>>>    kthread+0x112/0x130
>>>    ? kthread_flush_work_fn+0x10/0x10
>>>    ret_from_fork+0x35/0x40
>>>
>>> It was caused by that skb secpath is used in esp_output_done() after it's
>>> been released elsewhere.
>>>
>>> The tx path for esp offload is:
>>>
>>>   __dev_queue_xmit()->
>>>     validate_xmit_skb_list()->
>>>       validate_xmit_xfrm()->
>>>         esp_xmit()->
>>>           esp_output_tail()->
>>>             aead_request_set_callback(esp_output_done) <--[1]
>>>             crypto_aead_encrypt()  <--[2]
>>>
>>> In [1], .callback is set, and in [2] it will trigger the worker schedule,
>>> later on a kernel thread will call .callback(esp_output_done), as the call
>>> trace shows.
>>>
>>> But in validate_xmit_xfrm():
>>>
>>>   skb_list_walk_safe(skb, skb2, nskb) {
>>>     ...
>>>     err = x->type_offload->xmit(x, skb2, esp_features);  [esp_xmit]
>>>     ...
>>>   }
>>>
>>> When the err is -EINPROGRESS, which means this skb2 will be enqueued and
>>> later gets encrypted and sent out by .callback later in a kernel thread,
>>> skb2 should be removed fromt skb chain. Otherwise, it will get processed
>>> again outside validate_xmit_xfrm(), which could release skb secpath, and
>>> cause the panic above.
>>>
>>> This patch is to remove the skb from the chain when it's enqueued in
>>> cryptd_wq. While at it, remove the unnecessary 'if (!skb)' check.
>>>
>>> Fixes: 3dca3f38cfb8 ("xfrm: Separate ESP handling from segmentation for GRO packets.")
>>> Reported-by: Xiumei Mu <xmu@redhat.com>
>>> Signed-off-by: Xin Long <lucien.xin@gmail.com>
>>> ---
>>>  net/xfrm/xfrm_device.c | 8 ++++----
>>>  1 file changed, 4 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
>>> index 3231ec6..e2db468 100644
>>> --- a/net/xfrm/xfrm_device.c
>>> +++ b/net/xfrm/xfrm_device.c
>>> @@ -78,8 +78,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
>>>       int err;
>>>       unsigned long flags;
>>>       struct xfrm_state *x;
>>> -     struct sk_buff *skb2, *nskb;
>>>       struct softnet_data *sd;
>>> +     struct sk_buff *skb2, *nskb, *pskb = NULL;
>>>       netdev_features_t esp_features = features;
>>>       struct xfrm_offload *xo = xfrm_offload(skb);
>>>       struct sec_path *sp;
>>> @@ -168,14 +168,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
>>>               } else {
>>>                       if (skb == skb2)
>>>                               skb = nskb;
>>> -
>>> -                     if (!skb)
>>> -                             return NULL;
>>> +                     else
>>> +                             pskb->next = nskb;
>> pskb can be NULL on the first round?
> On the 1st round, skb == skb2.

Yes, I misread the patch, thanks.


>
>>
>>
>>>                       continue;
>>>               }
>>>
>>>               skb_push(skb2, skb2->data - skb_mac_header(skb2));
>>> +             pskb = skb2;
>>>       }
>>>
>>>       return skb;


[-- Attachment #2: pEpkey.asc --]
[-- Type: application/pgp-keys, Size: 3157 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-03-09 11:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-04  8:51 [PATCH ipsec] esp: remove the skb from the chain when it's enqueued in cryptd_wq Xin Long
2020-03-09  9:15 ` Steffen Klassert
2020-03-09 10:07 ` Mika Penttilä
2020-03-09 10:50   ` Xin Long
2020-03-09 11:06     ` Mika Penttilä

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).