> -----Original Message-----
> From: netdev-ow...@vger.kernel.org [mailto:netdev-ow...@vger.kernel.org]
> Subject: [PATCH 07/16] esp4: Reorganize esp_output
> 
> We need a fallback for ESP at layer 2, so split esp_output into generic
> functions that can be used at layer 3 and layer 2 and use them in
> esp_output. We also add esp_xmit which is used for the layer 2 fallback.
> 
> Signed-off-by: Steffen Klassert <steffen.klass...@secunet.com>
> ---
>  include/net/esp.h       |  16 +++
>  net/ipv4/esp4.c         | 341 ++++++++++++++++++++++++++-----------------
> -----
>  net/ipv4/esp4_offload.c | 102 +++++++++++++++
>  3 files changed, 301 insertions(+), 158 deletions(-)
> 

Steffen,

...

In the two places marked below:

> +static int esp_output(struct xfrm_state *x, struct sk_buff *skb) {
> +     int alen;
> +     int blksize;
> +     struct ip_esp_hdr *esph;
> +     struct crypto_aead *aead;
> +     struct esp_info esp;
> +
> +     esp.inplace = true;
> +
> +     esp.proto = *skb_mac_header(skb);
> +     *skb_mac_header(skb) = IPPROTO_ESP;
> +
> +     /* skb is pure payload to encrypt */
> +
> +     aead = x->data;
> +     alen = crypto_aead_authsize(aead);
> +
> +     esp.tfclen = 0;
> +     if (x->tfcpad) {
> +             struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
> +             u32 padto;
> +
> +             padto = min(x->tfcpad, esp4_get_mtu(x, dst-
> >child_mtu_cached));
> +             if (skb->len < padto)
> +                     esp.tfclen = padto - skb->len;
> +     }
> +     blksize = ALIGN(crypto_aead_blocksize(aead), 4);
> +     esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
> +     esp.plen = esp.clen - skb->len - esp.tfclen;
> +     esp.tailen = esp.tfclen + esp.plen + alen;
> +
> +     esp.esph = ip_esp_hdr(skb);
> +
> +     esp.nfrags = esp_output_head(x, skb, &esp);
> +     if (esp.nfrags < 0)
> +             return esp.nfrags;
> +
> +     esph = esp.esph;

Here

> +     esph->spi = x->id.spi;
> +
> +     esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
> +     esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
> +                              ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
> +
> +     skb_push(skb, -skb_network_offset(skb));
> +
> +     return esp_output_tail(x, skb, &esp);
> +}
> 

...

> +static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb,
> +netdev_features_t features) {
> +     int err;
> +     int alen;
> +     int blksize;
> +     struct xfrm_offload *xo;
> +     struct ip_esp_hdr *esph;
> +     struct crypto_aead *aead;
> +     struct esp_info esp;
> +     bool hw_offload = true;
> +
> +     esp.inplace = true;
> +
> +     xo = xfrm_offload(skb);
> +
> +     if (!xo)
> +             return -EINVAL;
> +
> +     if (!(features & NETIF_F_HW_ESP) ||
> +         (x->xso.offload_handle &&  x->xso.dev != skb->dev)) {
> +             xo->flags |= CRYPTO_FALLBACK;
> +             hw_offload = false;
> +     }
> +
> +     esp.proto = xo->proto;
> +
> +     /* skb is pure payload to encrypt */
> +
> +     aead = x->data;
> +     alen = crypto_aead_authsize(aead);
> +
> +     esp.tfclen = 0;
> +     /* XXX: Add support for tfc padding here. */
> +
> +     blksize = ALIGN(crypto_aead_blocksize(aead), 4);
> +     esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
> +     esp.plen = esp.clen - skb->len - esp.tfclen;
> +     esp.tailen = esp.tfclen + esp.plen + alen;
> +
> +     esp.esph = ip_esp_hdr(skb);
> +
> +
> +     if (!hw_offload || (hw_offload && !skb_is_gso(skb))) {
> +             esp.nfrags = esp_output_head(x, skb, &esp);
> +             if (esp.nfrags < 0)
> +                     return esp.nfrags;
> +     }
> +
> +     esph = esp.esph;

And here.

esp_output_head() might do an skb_cow, which then invalidates the esp.esph 
pointer and causes a crash later on.
I would expect the ip_esp_hdr() call to be after the esp_output_head() call.

But it seems like this pointer was saved here around the call to 
esp_output_head() on purpose.
Is that really so? 

Also, esp6/esp6_offload don't make use of esp_info.esph
Only esp_output_tail() uses it, and could have done everything it does without 
it.
So maybe it's un-needed?

I am still testing a fix patch for the crash, there may be also something 
similar on the RX path, though.

> +     esph->spi = x->id.spi;
> +
> +     skb_push(skb, -skb_network_offset(skb));
> +
> +     if (xo->flags & XFRM_GSO_SEGMENT) {
> +             esph->seq_no = htonl(xo->seq.low);
> +     } else {
> +             ip_hdr(skb)->tot_len = htons(skb->len);
> +             ip_send_check(ip_hdr(skb));
> +     }
> +
> +     if (hw_offload)
> +             return 0;
> +
> +     esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
> +
> +     err = esp_output_tail(x, skb, &esp);
> +     if (err < 0)
> +             return err;
> +
> +     secpath_reset(skb);
> +
> +     return 0;
> +}
> +

Reply via email to