384-mac80211-avoid-kernel-panic-when-building-AMSDU-from.patch 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. From: Sara Sharon <[email protected]>
  2. Date: Wed, 29 Aug 2018 08:57:02 +0200
  3. Subject: [PATCH] mac80211: avoid kernel panic when building AMSDU from
  4. non-linear SKB
  5. When building building AMSDU from non-linear SKB, we hit a
  6. kernel panic when trying to push the padding to the tail.
  7. Instead, put the padding at the head of the next subframe.
  8. This also fixes the A-MSDU subframes to not have the padding
  9. accounted in the length field and not have pad at all for
  10. the last subframe, both required by the spec.
  11. Fixes: 6e0456b54545 ("mac80211: add A-MSDU tx support")
  12. Signed-off-by: Sara Sharon <[email protected]>
  13. Reviewed-by: Lorenzo Bianconi <[email protected]>
  14. Signed-off-by: Johannes Berg <[email protected]>
  15. ---
  16. --- a/net/mac80211/tx.c
  17. +++ b/net/mac80211/tx.c
  18. @@ -3064,27 +3064,18 @@ void ieee80211_clear_fast_xmit(struct st
  19. }
  20. static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local,
  21. - struct sk_buff *skb, int headroom,
  22. - int *subframe_len)
  23. + struct sk_buff *skb, int headroom)
  24. {
  25. - int amsdu_len = *subframe_len + sizeof(struct ethhdr);
  26. - int padding = (4 - amsdu_len) & 3;
  27. -
  28. - if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) {
  29. + if (skb_headroom(skb) < headroom) {
  30. I802_DEBUG_INC(local->tx_expand_skb_head);
  31. - if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) {
  32. + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
  33. wiphy_debug(local->hw.wiphy,
  34. "failed to reallocate TX buffer\n");
  35. return false;
  36. }
  37. }
  38. - if (padding) {
  39. - *subframe_len += padding;
  40. - skb_put_zero(skb, padding);
  41. - }
  42. -
  43. return true;
  44. }
  45. @@ -3108,8 +3099,7 @@ static bool ieee80211_amsdu_prepare_head
  46. if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
  47. return true;
  48. - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr),
  49. - &subframe_len))
  50. + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr)))
  51. return false;
  52. data = skb_push(skb, sizeof(*amsdu_hdr));
  53. @@ -3176,7 +3166,8 @@ static bool ieee80211_amsdu_aggregate(st
  54. void *data;
  55. bool ret = false;
  56. unsigned int orig_len;
  57. - int n = 1, nfrags;
  58. + int n = 1, nfrags, pad = 0;
  59. + u16 hdrlen;
  60. if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
  61. return false;
  62. @@ -3228,8 +3219,19 @@ static bool ieee80211_amsdu_aggregate(st
  63. if (max_frags && nfrags > max_frags)
  64. goto out;
  65. - if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2,
  66. - &subframe_len))
  67. + /*
  68. + * Pad out the previous subframe to a multiple of 4 by adding the
  69. + * padding to the next one, that's being added. Note that head->len
  70. + * is the length of the full A-MSDU, but that works since each time
  71. + * we add a new subframe we pad out the previous one to a multiple
  72. + * of 4 and thus it no longer matters in the next round.
  73. + */
  74. + hdrlen = fast_tx->hdr_len - sizeof(rfc1042_header);
  75. + if ((head->len - hdrlen) & 3)
  76. + pad = 4 - ((head->len - hdrlen) & 3);
  77. +
  78. + if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) +
  79. + 2 + pad))
  80. goto out;
  81. ret = true;
  82. @@ -3241,6 +3243,8 @@ static bool ieee80211_amsdu_aggregate(st
  83. memcpy(data, &len, 2);
  84. memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header));
  85. + memset(skb_push(skb, pad), 0, pad);
  86. +
  87. head->len += skb->len;
  88. head->data_len += skb->len;
  89. *frag_tail = skb;