Public bug reported:

I had a support incident with a user of an Asus X551MA containing a
Realtek RTL8821AE WiFi card. After the kernel update from 3.13.0-24 to
3.13.0-30 there was a kernel Panic as soon as the wifi card began
scanning (photograph attached).

 I investigated the bug in detail and diagnosed the cause to commit
22bf70f which modifies a function prototype called by the RTL8821ae
driver but does not update the driver to call the alternative function.

Corrective patch attached.

RIP [<ffffffffa042ffe5>] rtl8821ae_rx_query_desc+0x1d5/0xa50 [rtl8821ae]

No changes were introduced in the rtl8821ae module between 3.13.0-24 and
3.13.0-30. The only changes were in mac80211, which rtl8821ae depends on
(along with cfg80211):

# check rtl8821ae
$ gitlog Ubuntu-3.13.0-24.47..Ubuntu-3.13.0-30.55 -- drivers/staging/rtl8821ae
# check mac80211
$ gitlog Ubuntu-3.13.0-24.47..Ubuntu-3.13.0-30.55 -- net/mac80211
7049ad3 Mon May 19 18:45:30 2014 +0100 Michael Braun mac80211: fix WPA with 
VLAN on AP side with ps-sta again
5d31275 Mon May 19 18:45:30 2014 +0100 Johannes Berg mac80211: fix suspend vs. 
authentication race
56f2ea4 Mon May 19 18:45:29 2014 +0100 Johannes Berg mac80211: fix potential 
use-after-free
22bf70f Tue Apr 15 15:27:46 2014 +0100 Johannes Berg mac80211: add length check 
in ieee80211_is_robust_mgmt_frame()
# check mac80211
$ gitlog Ubuntu-3.13.0-24.47..Ubuntu-3.13.0-30.55 -- net/wireless/
$

The faulting location is in function rx_query_desc() at offset 0x1d5.

$ objdump -d
/lib/modules/3.13.0-30-generic/kernel/drivers/staging/rtl8821ae/rtl8821ae.ko

0000000000033e40 <rtl8821ae_rx_query_desc>:

Faulting instruction is at 0x33e40 + 0x1d5 = 0x34015

Now I examine the debug-symbols of the module with:

$ gdb -d drivers/staging/rtl8821ae -d
drivers/staging/rtl8821ae/rtl8821ae
/usr/lib/debug/modules/3.13.0-30-generic/kernel/drivers/staging/rtl8821ae/rtl8821ae.dbgsym.ko

(gdb) info line rtl8821ae_rx_query_desc
Line 539 of 
"/build/buildd/linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/trx.c" starts 
at address 0x33e40 <rtl8821ae_rx_query_desc>
    and ends at 0x33e65 <rtl8821ae_rx_query_desc+37>.
(gdb) x/i 0x34015
    0x34015 <rtl8821ae_rx_query_desc+469>:       movzwl (%rdi),%esi
(gdb) disas rtl8821ae_rx_query_desc
...
    0x0000000000033ffe <+446>:   je     0x34641 <rtl8821ae_rx_query_desc+2049>
    0x0000000000034004 <+452>:   cmpl   $0x18,0x68(%rdx)
    0x0000000000034008 <+456>:   jbe    0x34268 <rtl8821ae_rx_query_desc+1064>
    0x000000000003400e <+462>:   mov    0xd8(%rdx),%rdi       /* 
hdr->frame_control */
    0x0000000000034015 <+469>:   movzwl (%rdi),%esi           /* FAULT %rdi 
invalid */
    0x0000000000034018 <+472>:   mov    %esi,%ecx
    0x000000000003401a <+474>:   and    $0xfc,%cx
    0x000000000003401f <+479>:   cmp    $0xa0,%cx
    0x0000000000034024 <+484>:   je     0x34068 <rtl8821ae_rx_query_desc+552>
...
(gdb) info line *0x34015
Line 2194 of "/build/buildd/linux-3.13.0/include/linux/ieee80211.h" starts at 
address 0x34015 <rtl8821ae_rx_query_desc+469>
    and ends at 0x34018 <rtl8821ae_rx_query_desc+472>.

---- include/linux/ieee80211.h -----
/**
  * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management 
frame
  * @hdr: the frame (buffer must include at least the first octet of payload)
  */
static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
{
   if (ieee80211_is_disassoc(hdr->frame_control) ||      /* LINE 2194 */
       ieee80211_is_deauth(hdr->frame_control))
     return true;


/**
  * ieee80211_is_disassoc - check if IEEE80211_FTYPE_MGMT && 
IEEE80211_STYPE_DISASSOC
  * @fc: frame control bytes in little-endian byteorder
  */
static inline int ieee80211_is_disassoc(__le16 fc)
{
   return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
          cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC);
}

----- drivers/staging/rtl8821ae/rtl8821ae/trx.c::rtl8821ae_rx_query_desc() -----
...
     if ((ieee80211_is_robust_mgmt_frame(hdr)) &&        /* FAULT LOCATION */
       (ieee80211_has_protected(hdr->frame_control)))
       rx_status->flag &= ~RX_FLAG_DECRYPTED;
     else
       rx_status->flag |= RX_FLAG_DECRYPTED;
   }
...
----- 8-< -----

On investigation it appears that gdb may have an incorrect debug reference for 
the location of ieee80211_is_robust_mgmt_frame() since the
location it references is for the underscore-prefix function 
_ieee80211_is_robust_mgmt_frame(). This may be due to both functions being 
inline.

The changes introduced in commit:

22bf70f Tue Apr 15 15:27:46 2014 +0100 Johannes Berg mac80211: add
length check in ieee80211_is_robust_mgmt_frame()

include renaming the existing

ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)

to

_ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)

and replacing the original function with one taking an skb, not
ieee80211_hdr:

+ * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame
+ * @skb: the skb containing the frame, length will be checked
+ */
+static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
+{
+       if (skb->len < 25)
+               return false;
+       return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
+}
+
+/**

Not being able to debug a live kernel with this hardware I'm unable to pursue 
much further, but commit 22bf70f suggests that the wrong function is now being 
called by rtl8821ae because it isn't 
patched to call the underscore version of the function as all other rtl* 
drivers were. If this is the case, the receiving function is expecting a skb.

The required change therefore probably should be:

$ git diff drivers/staging/rtl8821ae/rtl8821ae/trx.c
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/trx.c 
b/drivers/staging/rtl8821ae/rtl8821ae/trx.c
index 75ae438..963b55f 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/trx.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/trx.c
@@ -616,7 +616,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
                                 return false;
                 }

-               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                         (ieee80211_has_protected(hdr->frame_control)))
                         rx_status->flag &= ~RX_FLAG_DECRYPTED;
                 else
---

** Affects: linux (Ubuntu)
     Importance: High
         Status: Triaged


** Tags: amd64 regression-update staging trusty

** Attachment added: "Screenshot of Panic captured by user"
   
https://bugs.launchpad.net/bugs/1354469/+attachment/4172887/+files/Asus-X551MA.jpg

-- 
You received this bug notification because you are a member of Kernel
Packages, which is subscribed to linux in Ubuntu.
https://bugs.launchpad.net/bugs/1354469

Title:
  [3.13.0-30.55] rtl8821ae Kernel PANIC due to calling incorrect
  function

Status in “linux” package in Ubuntu:
  Triaged

Bug description:
  I had a support incident with a user of an Asus X551MA containing a
  Realtek RTL8821AE WiFi card. After the kernel update from 3.13.0-24 to
  3.13.0-30 there was a kernel Panic as soon as the wifi card began
  scanning (photograph attached).

   I investigated the bug in detail and diagnosed the cause to commit
  22bf70f which modifies a function prototype called by the RTL8821ae
  driver but does not update the driver to call the alternative
  function.

  Corrective patch attached.

  RIP [<ffffffffa042ffe5>] rtl8821ae_rx_query_desc+0x1d5/0xa50
  [rtl8821ae]

  No changes were introduced in the rtl8821ae module between 3.13.0-24
  and 3.13.0-30. The only changes were in mac80211, which rtl8821ae
  depends on (along with cfg80211):

  # check rtl8821ae
  $ gitlog Ubuntu-3.13.0-24.47..Ubuntu-3.13.0-30.55 -- drivers/staging/rtl8821ae
  # check mac80211
  $ gitlog Ubuntu-3.13.0-24.47..Ubuntu-3.13.0-30.55 -- net/mac80211
  7049ad3 Mon May 19 18:45:30 2014 +0100 Michael Braun mac80211: fix WPA with 
VLAN on AP side with ps-sta again
  5d31275 Mon May 19 18:45:30 2014 +0100 Johannes Berg mac80211: fix suspend 
vs. authentication race
  56f2ea4 Mon May 19 18:45:29 2014 +0100 Johannes Berg mac80211: fix potential 
use-after-free
  22bf70f Tue Apr 15 15:27:46 2014 +0100 Johannes Berg mac80211: add length 
check in ieee80211_is_robust_mgmt_frame()
  # check mac80211
  $ gitlog Ubuntu-3.13.0-24.47..Ubuntu-3.13.0-30.55 -- net/wireless/
  $

  The faulting location is in function rx_query_desc() at offset 0x1d5.

  $ objdump -d
  /lib/modules/3.13.0-30-generic/kernel/drivers/staging/rtl8821ae/rtl8821ae.ko

  0000000000033e40 <rtl8821ae_rx_query_desc>:

  Faulting instruction is at 0x33e40 + 0x1d5 = 0x34015

  Now I examine the debug-symbols of the module with:

  $ gdb -d drivers/staging/rtl8821ae -d
  drivers/staging/rtl8821ae/rtl8821ae
  
/usr/lib/debug/modules/3.13.0-30-generic/kernel/drivers/staging/rtl8821ae/rtl8821ae.dbgsym.ko

  (gdb) info line rtl8821ae_rx_query_desc
  Line 539 of 
"/build/buildd/linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/trx.c" starts 
at address 0x33e40 <rtl8821ae_rx_query_desc>
      and ends at 0x33e65 <rtl8821ae_rx_query_desc+37>.
  (gdb) x/i 0x34015
      0x34015 <rtl8821ae_rx_query_desc+469>:       movzwl (%rdi),%esi
  (gdb) disas rtl8821ae_rx_query_desc
  ...
      0x0000000000033ffe <+446>:   je     0x34641 <rtl8821ae_rx_query_desc+2049>
      0x0000000000034004 <+452>:   cmpl   $0x18,0x68(%rdx)
      0x0000000000034008 <+456>:   jbe    0x34268 <rtl8821ae_rx_query_desc+1064>
      0x000000000003400e <+462>:   mov    0xd8(%rdx),%rdi       /* 
hdr->frame_control */
      0x0000000000034015 <+469>:   movzwl (%rdi),%esi           /* FAULT %rdi 
invalid */
      0x0000000000034018 <+472>:   mov    %esi,%ecx
      0x000000000003401a <+474>:   and    $0xfc,%cx
      0x000000000003401f <+479>:   cmp    $0xa0,%cx
      0x0000000000034024 <+484>:   je     0x34068 <rtl8821ae_rx_query_desc+552>
  ...
  (gdb) info line *0x34015
  Line 2194 of "/build/buildd/linux-3.13.0/include/linux/ieee80211.h" starts at 
address 0x34015 <rtl8821ae_rx_query_desc+469>
      and ends at 0x34018 <rtl8821ae_rx_query_desc+472>.

  ---- include/linux/ieee80211.h -----
  /**
    * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management 
frame
    * @hdr: the frame (buffer must include at least the first octet of payload)
    */
  static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
  {
     if (ieee80211_is_disassoc(hdr->frame_control) ||      /* LINE 2194 */
         ieee80211_is_deauth(hdr->frame_control))
       return true;

  
  /**
    * ieee80211_is_disassoc - check if IEEE80211_FTYPE_MGMT && 
IEEE80211_STYPE_DISASSOC
    * @fc: frame control bytes in little-endian byteorder
    */
  static inline int ieee80211_is_disassoc(__le16 fc)
  {
     return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
            cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC);
  }

  ----- drivers/staging/rtl8821ae/rtl8821ae/trx.c::rtl8821ae_rx_query_desc() 
-----
  ...
       if ((ieee80211_is_robust_mgmt_frame(hdr)) &&        /* FAULT LOCATION */
         (ieee80211_has_protected(hdr->frame_control)))
         rx_status->flag &= ~RX_FLAG_DECRYPTED;
       else
         rx_status->flag |= RX_FLAG_DECRYPTED;
     }
  ...
  ----- 8-< -----

  On investigation it appears that gdb may have an incorrect debug reference 
for the location of ieee80211_is_robust_mgmt_frame() since the
  location it references is for the underscore-prefix function 
_ieee80211_is_robust_mgmt_frame(). This may be due to both functions being 
inline.

  The changes introduced in commit:

  22bf70f Tue Apr 15 15:27:46 2014 +0100 Johannes Berg mac80211: add
  length check in ieee80211_is_robust_mgmt_frame()

  include renaming the existing

  ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)

  to

  _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)

  and replacing the original function with one taking an skb, not
  ieee80211_hdr:

  + * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame
  + * @skb: the skb containing the frame, length will be checked
  + */
  +static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
  +{
  +       if (skb->len < 25)
  +               return false;
  +       return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
  +}
  +
  +/**

  Not being able to debug a live kernel with this hardware I'm unable to pursue 
much further, but commit 22bf70f suggests that the wrong function is now being 
called by rtl8821ae because it isn't 
  patched to call the underscore version of the function as all other rtl* 
drivers were. If this is the case, the receiving function is expecting a skb.

  The required change therefore probably should be:

  $ git diff drivers/staging/rtl8821ae/rtl8821ae/trx.c
  diff --git a/drivers/staging/rtl8821ae/rtl8821ae/trx.c 
b/drivers/staging/rtl8821ae/rtl8821ae/trx.c
  index 75ae438..963b55f 100644
  --- a/drivers/staging/rtl8821ae/rtl8821ae/trx.c
  +++ b/drivers/staging/rtl8821ae/rtl8821ae/trx.c
  @@ -616,7 +616,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
                                   return false;
                   }

  -               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
  +               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                           (ieee80211_has_protected(hdr->frame_control)))
                           rx_status->flag &= ~RX_FLAG_DECRYPTED;
                   else
  ---

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1354469/+subscriptions

-- 
Mailing list: https://launchpad.net/~kernel-packages
Post to     : kernel-packages@lists.launchpad.net
Unsubscribe : https://launchpad.net/~kernel-packages
More help   : https://help.launchpad.net/ListHelp

Reply via email to