diff mbox series

rtlwifi: rise completion at the last step of firmware callback

Message ID 20201214015238.3245-1-pkshih@realtek.com
State New
Headers show
Series rtlwifi: rise completion at the last step of firmware callback | expand

Commit Message

Ping-Ke Shih Dec. 14, 2020, 1:52 a.m. UTC
request_firmware_nowait() which schedules another work is used to load
firmware when USB is probing. If USB is unplugged before running the
firmware work, it goes disconnect ops, and then causes use-after-free.
Though we wait for completion of firmware work before freeing the hw,
firmware callback rises completion too early. So I move it to the
last step.

usb 5-1: Direct firmware load for rtlwifi/rtl8192cufw.bin failed with error -2
rtlwifi: Loading alternative firmware rtlwifi/rtl8192cufw.bin
rtlwifi: Selected firmware is not available

Comments

kernel test robot Dec. 14, 2020, 4:58 a.m. UTC | #1
Hi Ping-Ke,

I love your patch! Yet something to improve:

[auto build test ERROR on wireless-drivers-next/master]
[also build test ERROR on wireless-drivers/master v5.10 next-20201211]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Ping-Ke-Shih/rtlwifi-rise-completion-at-the-last-step-of-firmware-callback/20201214-095732
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: m68k-randconfig-r035-20201214 (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/d6328e8677e1f940022051a1cb58c2b36731a571
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Ping-Ke-Shih/rtlwifi-rise-completion-at-the-last-step-of-firmware-callback/20201214-095732
        git checkout d6328e8677e1f940022051a1cb58c2b36731a571
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/net/wireless/realtek/rtlwifi/core.c: In function 'rtl_fw_do_work':
>> drivers/net/wireless/realtek/rtlwifi/core.c:112:1: error: 'exit' undeclared (first use in this function)
     112 | exit;
         | ^~~~
   drivers/net/wireless/realtek/rtlwifi/core.c:112:1: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/net/wireless/realtek/rtlwifi/core.c:99:3: error: label 'exit' used but not defined
      99 |   goto exit;
         |   ^~~~

vim +/exit +112 drivers/net/wireless/realtek/rtlwifi/core.c

    71	
    72	static void rtl_fw_do_work(const struct firmware *firmware, void *context,
    73				   bool is_wow)
    74	{
    75		struct ieee80211_hw *hw = context;
    76		struct rtl_priv *rtlpriv = rtl_priv(hw);
    77		int err;
    78	
    79		rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
    80			"Firmware callback routine entered!\n");
    81		if (!firmware) {
    82			if (rtlpriv->cfg->alt_fw_name) {
    83				err = request_firmware(&firmware,
    84						       rtlpriv->cfg->alt_fw_name,
    85						       rtlpriv->io.dev);
    86				pr_info("Loading alternative firmware %s\n",
    87					rtlpriv->cfg->alt_fw_name);
    88				if (!err)
    89					goto found_alt;
    90			}
    91			pr_err("Selected firmware is not available\n");
    92			rtlpriv->max_fw_size = 0;
    93			goto exit;
    94		}
    95	found_alt:
    96		if (firmware->size > rtlpriv->max_fw_size) {
    97			pr_err("Firmware is too big!\n");
    98			release_firmware(firmware);
  > 99			goto exit;
   100		}
   101		if (!is_wow) {
   102			memcpy(rtlpriv->rtlhal.pfirmware, firmware->data,
   103			       firmware->size);
   104			rtlpriv->rtlhal.fwsize = firmware->size;
   105		} else {
   106			memcpy(rtlpriv->rtlhal.wowlan_firmware, firmware->data,
   107			       firmware->size);
   108			rtlpriv->rtlhal.wowlan_fwsize = firmware->size;
   109		}
   110		release_firmware(firmware);
   111	
 > 112	exit;
   113		complete(&rtlpriv->firmware_loading_complete);
   114	}
   115	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Dec. 14, 2020, 5:42 a.m. UTC | #2
Hi Ping-Ke,

I love your patch! Yet something to improve:

[auto build test ERROR on wireless-drivers-next/master]
[also build test ERROR on wireless-drivers/master v5.10 next-20201211]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Ping-Ke-Shih/rtlwifi-rise-completion-at-the-last-step-of-firmware-callback/20201214-095732
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: alpha-allmodconfig (attached as .config)
compiler: alpha-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/d6328e8677e1f940022051a1cb58c2b36731a571
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Ping-Ke-Shih/rtlwifi-rise-completion-at-the-last-step-of-firmware-callback/20201214-095732
        git checkout d6328e8677e1f940022051a1cb58c2b36731a571
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=alpha 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/net/wireless/realtek/rtlwifi/core.c: In function 'rtl_fw_do_work':
>> drivers/net/wireless/realtek/rtlwifi/core.c:112:1: error: 'exit' undeclared (first use in this function)
     112 | exit;
         | ^~~~
   drivers/net/wireless/realtek/rtlwifi/core.c:112:1: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/net/wireless/realtek/rtlwifi/core.c:99:3: error: label 'exit' used but not defined
      99 |   goto exit;
         |   ^~~~

vim +/exit +112 drivers/net/wireless/realtek/rtlwifi/core.c

    71	
    72	static void rtl_fw_do_work(const struct firmware *firmware, void *context,
    73				   bool is_wow)
    74	{
    75		struct ieee80211_hw *hw = context;
    76		struct rtl_priv *rtlpriv = rtl_priv(hw);
    77		int err;
    78	
    79		rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
    80			"Firmware callback routine entered!\n");
    81		if (!firmware) {
    82			if (rtlpriv->cfg->alt_fw_name) {
    83				err = request_firmware(&firmware,
    84						       rtlpriv->cfg->alt_fw_name,
    85						       rtlpriv->io.dev);
    86				pr_info("Loading alternative firmware %s\n",
    87					rtlpriv->cfg->alt_fw_name);
    88				if (!err)
    89					goto found_alt;
    90			}
    91			pr_err("Selected firmware is not available\n");
    92			rtlpriv->max_fw_size = 0;
    93			goto exit;
    94		}
    95	found_alt:
    96		if (firmware->size > rtlpriv->max_fw_size) {
    97			pr_err("Firmware is too big!\n");
    98			release_firmware(firmware);
  > 99			goto exit;
   100		}
   101		if (!is_wow) {
   102			memcpy(rtlpriv->rtlhal.pfirmware, firmware->data,
   103			       firmware->size);
   104			rtlpriv->rtlhal.fwsize = firmware->size;
   105		} else {
   106			memcpy(rtlpriv->rtlhal.wowlan_firmware, firmware->data,
   107			       firmware->size);
   108			rtlpriv->rtlhal.wowlan_fwsize = firmware->size;
   109		}
   110		release_firmware(firmware);
   111	
 > 112	exit;
   113		complete(&rtlpriv->firmware_loading_complete);
   114	}
   115	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

==================================================================
BUG: KASAN: use-after-free in rtl_fw_do_work.cold+0x68/0x6a drivers/net/wireless/realtek/rtlwifi/core.c:93
Write of size 4 at addr ffff8881454cff50 by task kworker/0:6/7379

CPU: 0 PID: 7379 Comm: kworker/0:6 Not tainted 5.10.0-rc7-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Workqueue: events request_firmware_work_func
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x107/0x163 lib/dump_stack.c:118
 print_address_description.constprop.0.cold+0xae/0x4c8 mm/kasan/report.c:385
 __kasan_report mm/kasan/report.c:545 [inline]
 kasan_report.cold+0x1f/0x37 mm/kasan/report.c:562
 rtl_fw_do_work.cold+0x68/0x6a drivers/net/wireless/realtek/rtlwifi/core.c:93
 request_firmware_work_func+0x12c/0x230 drivers/base/firmware_loader/main.c:1079
 process_one_work+0x933/0x1520 kernel/workqueue.c:2272
 worker_thread+0x64c/0x1120 kernel/workqueue.c:2418
 kthread+0x38c/0x460 kernel/kthread.c:292
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:296

The buggy address belongs to the page:
page:00000000f54435b3 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1454cf
flags: 0x200000000000000()
raw: 0200000000000000 0000000000000000 ffffea00051533c8 0000000000000000
raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff8881454cfe00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff8881454cfe80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff8881454cff00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
                                                 ^
 ffff8881454cff80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff8881454d0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

Reported-by: syzbot+65be4277f3c489293939@syzkaller.appspotmail.com
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtlwifi/core.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c
index a7259dbc953d..67550cab716a 100644
--- a/drivers/net/wireless/realtek/rtlwifi/core.c
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -78,7 +78,6 @@  static void rtl_fw_do_work(const struct firmware *firmware, void *context,
 
 	rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
 		"Firmware callback routine entered!\n");
-	complete(&rtlpriv->firmware_loading_complete);
 	if (!firmware) {
 		if (rtlpriv->cfg->alt_fw_name) {
 			err = request_firmware(&firmware,
@@ -91,13 +90,13 @@  static void rtl_fw_do_work(const struct firmware *firmware, void *context,
 		}
 		pr_err("Selected firmware is not available\n");
 		rtlpriv->max_fw_size = 0;
-		return;
+		goto exit;
 	}
 found_alt:
 	if (firmware->size > rtlpriv->max_fw_size) {
 		pr_err("Firmware is too big!\n");
 		release_firmware(firmware);
-		return;
+		goto exit;
 	}
 	if (!is_wow) {
 		memcpy(rtlpriv->rtlhal.pfirmware, firmware->data,
@@ -109,6 +108,9 @@  static void rtl_fw_do_work(const struct firmware *firmware, void *context,
 		rtlpriv->rtlhal.wowlan_fwsize = firmware->size;
 	}
 	release_firmware(firmware);
+
+exit;
+	complete(&rtlpriv->firmware_loading_complete);
 }
 
 void rtl_fw_cb(const struct firmware *firmware, void *context)