2019-08-28 16:20:33

by Wen Gong

[permalink] [raw]
Subject: [PATCH v3 1/8] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet

When the FW bundles multiple packets, pkt->act_len may be incorrect
as it refers to the first packet only (however, the FW will only
bundle packets that fit into the same pkt->alloc_len).

Before this patch, the skb length would be set (incorrectly) to
pkt->act_len in ath10k_sdio_mbox_rx_packet, and then later manually
adjusted in ath10k_sdio_mbox_rx_process_packet.

The first problem is that ath10k_sdio_mbox_rx_process_packet does not
use proper skb_put commands to adjust the length (it directly changes
skb->len), so we end up with a mismatch between skb->head + skb->tail
and skb->data + skb->len. This is quite serious, and causes corruptions
in the TCP stack, as the stack tries to coalesce packets, and relies
on skb->tail being correct (that is, skb_tail_pointer must point to
the first byte_after_ the data).

Instead of re-adjusting the size in ath10k_sdio_mbox_rx_process_packet,
this moves the code to ath10k_sdio_mbox_rx_packet, and also add a
bounds check, as skb_put would crash the kernel if not enough space is
available.

Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.

Signed-off-by: Nicolas Boichat <[email protected]>
Signed-off-by: Wen Gong <[email protected]>
---
v2:no this patch
v2:new added
drivers/net/wireless/ath/ath10k/sdio.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 8ed4fbd..1127e44 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
enum ath10k_htc_ep_id eid;
- u16 payload_len;
u8 *trailer;
int ret;

- payload_len = le16_to_cpu(htc_hdr->len);
- skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
-
if (trailer_present) {
- trailer = skb->data + sizeof(*htc_hdr) +
- payload_len - htc_hdr->trailer_len;
+ trailer = skb->data + skb->len - htc_hdr->trailer_len;

eid = pipe_id_to_eid(htc_hdr->eid);

@@ -632,13 +627,29 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
struct sk_buff *skb = pkt->skb;
+ struct ath10k_htc_hdr *htc_hdr;
int ret;

ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
skb->data, pkt->alloc_len);
+
+ if (!ret) {
+ /* Update actual length. The original length may be incorrect,
+ * as the FW will bundle multiple packets as long as their sizes
+ * fit within the same aligned length (pkt->alloc_len).
+ */
+ htc_hdr = (struct ath10k_htc_hdr *)skb->data;
+ pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
+ if (pkt->act_len <= pkt->alloc_len) {
+ skb_put(skb, pkt->act_len);
+ } else {
+ ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
+ pkt->act_len, pkt->alloc_len);
+ ret = -EMSGSIZE;
+ }
+ }
+
pkt->status = ret;
- if (!ret)
- skb_put(skb, pkt->act_len);

return ret;
}
--
1.9.1


2019-08-30 02:54:26

by Nicolas Boichat

[permalink] [raw]
Subject: Re: [PATCH v3 1/8] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet

On Thu, Aug 29, 2019 at 12:18 AM Wen Gong <[email protected]> wrote:
>
> When the FW bundles multiple packets, pkt->act_len may be incorrect
> as it refers to the first packet only (however, the FW will only
> bundle packets that fit into the same pkt->alloc_len).
>
> Before this patch, the skb length would be set (incorrectly) to
> pkt->act_len in ath10k_sdio_mbox_rx_packet, and then later manually
> adjusted in ath10k_sdio_mbox_rx_process_packet.
>
> The first problem is that ath10k_sdio_mbox_rx_process_packet does not
> use proper skb_put commands to adjust the length (it directly changes
> skb->len), so we end up with a mismatch between skb->head + skb->tail
> and skb->data + skb->len. This is quite serious, and causes corruptions
> in the TCP stack, as the stack tries to coalesce packets, and relies
> on skb->tail being correct (that is, skb_tail_pointer must point to
> the first byte_after_ the data).
>
> Instead of re-adjusting the size in ath10k_sdio_mbox_rx_process_packet,
> this moves the code to ath10k_sdio_mbox_rx_packet, and also add a
> bounds check, as skb_put would crash the kernel if not enough space is
> available.
>
> Tested with QCA6174 SDIO with firmware
> WLAN.RMH.4.4.1-00007-QCARMSWP-1.
>
> Signed-off-by: Nicolas Boichat <[email protected]>
> Signed-off-by: Wen Gong <[email protected]>

You are not the author of this patch, please reset the author in your
git tree and resend.

Once you do that, the first line should say:
From: Nicolas Boichat <[email protected]>

Without this fix:
NACKed-by: Nicolas Boichat <[email protected]>

> ---
> v2:no this patch
> v2:new added
> drivers/net/wireless/ath/ath10k/sdio.c | 27 +++++++++++++++++++--------
> 1 file changed, 19 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
> index 8ed4fbd..1127e44 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.c
> +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> @@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
> struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
> bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
> enum ath10k_htc_ep_id eid;
> - u16 payload_len;
> u8 *trailer;
> int ret;
>
> - payload_len = le16_to_cpu(htc_hdr->len);
> - skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
> -
> if (trailer_present) {
> - trailer = skb->data + sizeof(*htc_hdr) +
> - payload_len - htc_hdr->trailer_len;
> + trailer = skb->data + skb->len - htc_hdr->trailer_len;
>
> eid = pipe_id_to_eid(htc_hdr->eid);
>
> @@ -632,13 +627,29 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
> {
> struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
> struct sk_buff *skb = pkt->skb;
> + struct ath10k_htc_hdr *htc_hdr;
> int ret;
>
> ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> skb->data, pkt->alloc_len);
> +
> + if (!ret) {
> + /* Update actual length. The original length may be incorrect,
> + * as the FW will bundle multiple packets as long as their sizes
> + * fit within the same aligned length (pkt->alloc_len).
> + */
> + htc_hdr = (struct ath10k_htc_hdr *)skb->data;
> + pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
> + if (pkt->act_len <= pkt->alloc_len) {
> + skb_put(skb, pkt->act_len);
> + } else {
> + ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
> + pkt->act_len, pkt->alloc_len);
> + ret = -EMSGSIZE;
> + }
> + }
> +
> pkt->status = ret;
> - if (!ret)
> - skb_put(skb, pkt->act_len);
>
> return ret;
> }
> --
> 1.9.1
>

2019-08-30 02:58:39

by Nicolas Boichat

[permalink] [raw]
Subject: Re: [PATCH v3 1/8] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet

On Fri, Aug 30, 2019 at 10:53 AM Nicolas Boichat <[email protected]> wrote:
>
> On Thu, Aug 29, 2019 at 12:18 AM Wen Gong <[email protected]> wrote:
> >
> > When the FW bundles multiple packets, pkt->act_len may be incorrect
> > as it refers to the first packet only (however, the FW will only
> > bundle packets that fit into the same pkt->alloc_len).
> >
> > Before this patch, the skb length would be set (incorrectly) to
> > pkt->act_len in ath10k_sdio_mbox_rx_packet, and then later manually
> > adjusted in ath10k_sdio_mbox_rx_process_packet.
> >
> > The first problem is that ath10k_sdio_mbox_rx_process_packet does not
> > use proper skb_put commands to adjust the length (it directly changes
> > skb->len), so we end up with a mismatch between skb->head + skb->tail
> > and skb->data + skb->len. This is quite serious, and causes corruptions
> > in the TCP stack, as the stack tries to coalesce packets, and relies
> > on skb->tail being correct (that is, skb_tail_pointer must point to
> > the first byte_after_ the data).
> >
> > Instead of re-adjusting the size in ath10k_sdio_mbox_rx_process_packet,
> > this moves the code to ath10k_sdio_mbox_rx_packet, and also add a
> > bounds check, as skb_put would crash the kernel if not enough space is
> > available.
> >
> > Tested with QCA6174 SDIO with firmware
> > WLAN.RMH.4.4.1-00007-QCARMSWP-1.
> >
> > Signed-off-by: Nicolas Boichat <[email protected]>
> > Signed-off-by: Wen Gong <[email protected]>
>
> You are not the author of this patch, please reset the author in your
> git tree and resend.
>
> Once you do that, the first line should say:
> From: Nicolas Boichat <[email protected]>
>
> Without this fix:
> NACKed-by: Nicolas Boichat <[email protected]>
>

Also you dropped the Fixes line:
Fixes: 8530b4e7b22bc3b ("ath10k: sdio: set skb len for all rx packets")

> > ---
> > v2:no this patch
> > v2:new added
> > drivers/net/wireless/ath/ath10k/sdio.c | 27 +++++++++++++++++++--------
> > 1 file changed, 19 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
> > index 8ed4fbd..1127e44 100644
> > --- a/drivers/net/wireless/ath/ath10k/sdio.c
> > +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> > @@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
> > struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
> > bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
> > enum ath10k_htc_ep_id eid;
> > - u16 payload_len;
> > u8 *trailer;
> > int ret;
> >
> > - payload_len = le16_to_cpu(htc_hdr->len);
> > - skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
> > -
> > if (trailer_present) {
> > - trailer = skb->data + sizeof(*htc_hdr) +
> > - payload_len - htc_hdr->trailer_len;
> > + trailer = skb->data + skb->len - htc_hdr->trailer_len;
> >
> > eid = pipe_id_to_eid(htc_hdr->eid);
> >
> > @@ -632,13 +627,29 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
> > {
> > struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
> > struct sk_buff *skb = pkt->skb;
> > + struct ath10k_htc_hdr *htc_hdr;
> > int ret;
> >
> > ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> > skb->data, pkt->alloc_len);
> > +
> > + if (!ret) {
> > + /* Update actual length. The original length may be incorrect,
> > + * as the FW will bundle multiple packets as long as their sizes
> > + * fit within the same aligned length (pkt->alloc_len).
> > + */
> > + htc_hdr = (struct ath10k_htc_hdr *)skb->data;
> > + pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
> > + if (pkt->act_len <= pkt->alloc_len) {
> > + skb_put(skb, pkt->act_len);
> > + } else {
> > + ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
> > + pkt->act_len, pkt->alloc_len);
> > + ret = -EMSGSIZE;
> > + }
> > + }
> > +
> > pkt->status = ret;
> > - if (!ret)
> > - skb_put(skb, pkt->act_len);
> >
> > return ret;
> > }
> > --
> > 1.9.1
> >

2019-09-04 02:44:35

by Wen Gong

[permalink] [raw]
Subject: RE: [PATCH v3 1/8] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet

> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Wen Gong
> Sent: Wednesday, August 28, 2019 9:16 PM
> To: [email protected]
> Cc: [email protected]
> Subject: [EXT] [PATCH v3 1/8] ath10k: adjust skb length in
> ath10k_sdio_mbox_rx_packet
>
Patch v4 sent, https://patchwork.kernel.org/patch/11126221/
>
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k