2017-05-12 16:42:41

by Brian Norris

[permalink] [raw]
Subject: [PATCH 01/11] mwifiex: fixup error cases in mwifiex_add_virtual_intf()

If we fail to add an interface in mwifiex_add_virtual_intf(), we might
hit a BUG_ON() in the networking code, because we didn't tear things
down properly. Among the problems:

(a) when failing to allocate workqueues, we fail to unregister the
netdev before calling free_netdev()
(b) even if we do try to unregister the netdev, we're still holding the
rtnl lock, so the device never properly unregistered; we'll be at
state NETREG_UNREGISTERING, and then hit free_netdev()'s:
BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
(c) we're allocating some dependent resources (e.g., DFS workqueues)
after we've registered the interface; this may or may not cause
problems, but it's good practice to allocate these before registering
(d) we're not even trying to unwind anything when mwifiex_send_cmd() or
mwifiex_sta_init_cmd() fail

To fix these issues, let's:

* add a stacked set of error handling labels, to keep error handling
consistent and properly ordered (resolving (a) and (d))
* move the workqueue allocations before the registration (to resolve
(c); also resolves (b) by avoiding error cases where we have to
unregister)

[Incidentally, it's pretty easy to interrupt the alloc_workqueue() in,
e.g., the following:

iw phy phy0 interface add mlan0 type station

by sending it SIGTERM.]

This bugfix covers commits like commit 7d652034d1a0 ("mwifiex: channel
switch support for mwifiex"), but parts of this bug exist all the way
back to the introduction of dynamic interface handling in commit
93a1df48d224 ("mwifiex: add cfg80211 handlers add/del_virtual_intf").

Cc: <[email protected]>
Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 71 ++++++++++++-------------
1 file changed, 35 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 7ec06bf13413..025bc06a19d6 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -2964,10 +2964,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
if (!dev) {
mwifiex_dbg(adapter, ERROR,
"no memory available for netdevice\n");
- memset(&priv->wdev, 0, sizeof(priv->wdev));
- priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
- priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
- return ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto err_alloc_netdev;
}

mwifiex_init_priv_params(priv, dev);
@@ -2976,11 +2974,11 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
HostCmd_ACT_GEN_SET, 0, NULL, true);
if (ret)
- return ERR_PTR(ret);
+ goto err_set_bss_mode;

ret = mwifiex_sta_init_cmd(priv, false, false);
if (ret)
- return ERR_PTR(ret);
+ goto err_sta_init;

mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv);
if (adapter->is_hw_11ac_capable)
@@ -3011,31 +3009,14 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,

SET_NETDEV_DEV(dev, adapter->dev);

- /* Register network device */
- if (register_netdevice(dev)) {
- mwifiex_dbg(adapter, ERROR,
- "cannot register virtual network device\n");
- free_netdev(dev);
- priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->netdev = NULL;
- memset(&priv->wdev, 0, sizeof(priv->wdev));
- priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
- return ERR_PTR(-EFAULT);
- }
-
priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s",
WQ_HIGHPRI |
WQ_MEM_RECLAIM |
WQ_UNBOUND, 1, name);
if (!priv->dfs_cac_workqueue) {
- mwifiex_dbg(adapter, ERROR,
- "cannot register virtual network device\n");
- free_netdev(dev);
- priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->netdev = NULL;
- memset(&priv->wdev, 0, sizeof(priv->wdev));
- priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
- return ERR_PTR(-ENOMEM);
+ mwifiex_dbg(adapter, ERROR, "cannot alloc DFS CAC queue\n");
+ ret = -ENOMEM;
+ goto err_alloc_cac;
}

INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
@@ -3044,16 +3025,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
WQ_HIGHPRI | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1, name);
if (!priv->dfs_chan_sw_workqueue) {
- mwifiex_dbg(adapter, ERROR,
- "cannot register virtual network device\n");
- free_netdev(dev);
- priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->netdev = NULL;
- memset(&priv->wdev, 0, sizeof(priv->wdev));
- priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
- destroy_workqueue(priv->dfs_cac_workqueue);
- priv->dfs_cac_workqueue = NULL;
- return ERR_PTR(-ENOMEM);
+ mwifiex_dbg(adapter, ERROR, "cannot alloc DFS channel sw queue\n");
+ ret = -ENOMEM;
+ goto err_alloc_chsw;
}

INIT_DELAYED_WORK(&priv->dfs_chan_sw_work,
@@ -3061,6 +3035,13 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,

sema_init(&priv->async_sem, 1);

+ /* Register network device */
+ if (register_netdevice(dev)) {
+ mwifiex_dbg(adapter, ERROR, "cannot register network device\n");
+ ret = -EFAULT;
+ goto err_reg_netdev;
+ }
+
mwifiex_dbg(adapter, INFO,
"info: %s: Marvell 802.11 Adapter\n", dev->name);

@@ -3081,11 +3062,29 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
adapter->curr_iface_comb.p2p_intf++;
break;
default:
+ /* This should be dead code; checked above */
mwifiex_dbg(adapter, ERROR, "type not supported\n");
return ERR_PTR(-EINVAL);
}

return &priv->wdev;
+
+err_reg_netdev:
+ destroy_workqueue(priv->dfs_chan_sw_workqueue);
+ priv->dfs_chan_sw_workqueue = NULL;
+err_alloc_chsw:
+ destroy_workqueue(priv->dfs_cac_workqueue);
+ priv->dfs_cac_workqueue = NULL;
+err_alloc_cac:
+ free_netdev(dev);
+ priv->netdev = NULL;
+err_sta_init:
+err_set_bss_mode:
+err_alloc_netdev:
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);

--
2.13.0.rc2.291.g57267f2277-goog


2017-05-12 16:42:34

by Brian Norris

[permalink] [raw]
Subject: [PATCH 10/11] mwifiex: pcie: remove useless pdev check

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 5 -----
1 file changed, 5 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index ac62bce50e96..d7e563a622f7 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2380,11 +2380,6 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
struct pcie_service_card *card;
struct mwifiex_adapter *adapter;

- if (!pdev) {
- pr_err("info: %s: pdev is NULL\n", __func__);
- goto exit;
- }
-
card = pci_get_drvdata(pdev);

if (!card->adapter) {
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:33

by Brian Norris

[permalink] [raw]
Subject: [PATCH 09/11] mwifiex: 11h: drop unnecessary check for '!priv'

These pointers are retrieved via container_of(). There's no way they are
NULL.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/11h.c | 6 ------
1 file changed, 6 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c
index 366eb4991a7d..238accfe4f41 100644
--- a/drivers/net/wireless/marvell/mwifiex/11h.c
+++ b/drivers/net/wireless/marvell/mwifiex/11h.c
@@ -128,9 +128,6 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work)
container_of(delayed_work, struct mwifiex_private,
dfs_cac_work);

- if (WARN_ON(!priv))
- return;
-
chandef = priv->dfs_chandef;
if (priv->wdev.cac_started) {
mwifiex_dbg(priv->adapter, MSG,
@@ -289,9 +286,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
container_of(delayed_work, struct mwifiex_private,
dfs_chan_sw_work);

- if (WARN_ON(!priv))
- return;
-
bss_cfg = &priv->bss_cfg;
if (!bss_cfg->beacon_period) {
mwifiex_dbg(priv->adapter, ERROR,
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:35

by Brian Norris

[permalink] [raw]
Subject: [PATCH 11/11] mwifiex: pcie: stop setting/clearing 'surprise_removed'

These are already handled by mwifiex_shutdown_sw() and
mwifiex_reinit_sw(). Ideally, we'll kill the flag entirely eventually,
as I suspect it breeds race conditions.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index d7e563a622f7..da042d15f8f0 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -370,7 +370,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
* PCIe and HW.
*/
mwifiex_shutdown_sw(adapter);
- adapter->surprise_removed = true;
clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
} else {
@@ -378,7 +377,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
* after performing FLR respectively. Reconfigure the software
* and firmware including firmware redownload
*/
- adapter->surprise_removed = false;
ret = mwifiex_reinit_sw(adapter);
if (ret) {
dev_err(&pdev->dev, "reinit failed: %d\n", ret);
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:27

by Brian Norris

[permalink] [raw]
Subject: [PATCH 02/11] mwifiex: Don't release tx_ba_stream_tbl_lock while iterating

From: Douglas Anderson <[email protected]>

Despite the macro list_for_each_entry_safe() having the word "safe" in
the name, it's still not actually safe to release the list spinlock
while iterating over the list. The "safe" in the macro name actually
only means that it's safe to delete the current entry while iterating
over the list.

Releasing the spinlock while iterating over the list means that someone
else could come in and adjust the list while we don't have the
spinlock. If they do that it can totally mix up our iteration and fully
corrupt the list. Later iterating over a corrupted list while holding a
spinlock and having IRQs off can cause all sorts of hard to debug
problems.

As evidenced by the other call to
mwifiex_11n_delete_tx_ba_stream_tbl_entry() in
mwifiex_11n_delete_all_tx_ba_stream_tbl(), it's actually safe to skip
the spinlock release. Let's do that.

No known problems are fixed by this patch, but it could fix all sorts of
weird problems and it should be very safe.

Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/11n.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c
index c174e79e6df2..c75b6abf16a0 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n.c
@@ -764,14 +764,9 @@ void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
return;

spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
- list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) {
- if (!memcmp(tbl->ra, ra, ETH_ALEN)) {
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
- flags);
+ list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list)
+ if (!memcmp(tbl->ra, ra, ETH_ALEN))
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl);
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
- }
- }
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);

return;
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:32

by Brian Norris

[permalink] [raw]
Subject: [PATCH 08/11] mwifiex: remove redundant 'adapter' check in mwifiex_adapter_cleanup

We're using 'adapter' right before calling this. Stop being
unnecessarily paranoid.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/init.c | 5 -----
1 file changed, 5 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 2bff87bd76a6..80bdf1c5f77f 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -409,11 +409,6 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
static void
mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
{
- if (!adapter) {
- pr_err("%s: adapter is NULL\n", __func__);
- return;
- }
-
del_timer(&adapter->wakeup_timer);
mwifiex_cancel_all_pending_cmd(adapter);
wake_up_interruptible(&adapter->cmd_wait_q.wait);
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:29

by Brian Norris

[permalink] [raw]
Subject: [PATCH 05/11] mwifiex: don't drop lock between list-retrieval / list-deletion

mwifiex_exec_next_cmd() seems to have a classic TOCTOU race, where we
drop the list lock in between retrieving the next command and deleting
it from the list. This potentially leaves room for someone else to also
retrieve / steal this node from the list (e.g.,
mwifiex_cancel_all_pending_cmd()).

Let's keep holding the lock while we do our 'ps_state' sanity checks.
There should be no harm in continuing to hold this lock for a bit more.

Noticed only by code inspection.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/cmdevt.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 5fd6c53d7b06..95221306a4e5 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -761,8 +761,6 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
}
cmd_node = list_first_entry(&adapter->cmd_pending_q,
struct cmd_ctrl_node, list);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
- cmd_pending_q_flags);

host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
priv = cmd_node->priv;
@@ -771,11 +769,12 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
mwifiex_dbg(adapter, ERROR,
"%s: cannot send cmd in sleep state,\t"
"this should not happen\n", __func__);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+ cmd_pending_q_flags);
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
return ret;
}

- spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
cmd_pending_q_flags);
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:46

by Brian Norris

[permalink] [raw]
Subject: [PATCH 07/11] mwifiex: remove useless 'mwifiex_lock'

If mwifiex_shutdown_drv() is racing with another mwifiex_shutdown_drv(),
we *really* have problems. Kill the lock.

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/init.c | 4 ----
drivers/net/wireless/marvell/mwifiex/main.h | 2 --
2 files changed, 6 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 2ada202c72ec..2bff87bd76a6 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -439,7 +439,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
struct mwifiex_private *priv;
s32 i, j;

- spin_lock_init(&adapter->mwifiex_lock);
spin_lock_init(&adapter->int_lock);
spin_lock_init(&adapter->main_proc_lock);
spin_lock_init(&adapter->mwifiex_cmd_lock);
@@ -693,11 +692,8 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)

spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);

- spin_lock(&adapter->mwifiex_lock);
-
mwifiex_adapter_cleanup(adapter);

- spin_unlock(&adapter->mwifiex_lock);
adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY;
}

diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index bb2a467d8b13..66c184936c95 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -870,8 +870,6 @@ struct mwifiex_adapter {
bool rx_locked;
bool main_locked;
struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
- /* spin lock for init/shutdown */
- spinlock_t mwifiex_lock;
/* spin lock for main process */
spinlock_t main_proc_lock;
u32 mwifiex_processing;
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:35

by Brian Norris

[permalink] [raw]
Subject: [PATCH 06/11] mwifiex: don't leak stashed beacon buffer on reset

When removing or resetting an mwifiex device, we don't remember to free
the saved beacon buffer. Use the (somewhat misleadingly-named)
mwifiex_free_priv() helper to handle this.

Noticed by kmemleak during tests:

echo 1 > /sys/bus/pci/devices/.../reset

unreferenced object 0xffffffc09d034a00 (size 256):
...
backtrace:
[<ffffffc0003cdce4>] create_object+0x228/0x3c4
[<ffffffc000c0b9d8>] kmemleak_alloc+0x54/0x88
[<ffffffc0003c0848>] __kmalloc+0x1cc/0x2dc
[<ffffffbffc1500c4>] mwifiex_save_curr_bcn+0x80/0x308 [mwifiex]
[<ffffffbffc1516b8>] mwifiex_ret_802_11_associate+0x4ec/0x5fc [mwifiex]
[<ffffffbffc15da90>] mwifiex_process_sta_cmdresp+0xaf8/0x1fa4 [mwifiex]
[<ffffffbffc1411e0>] mwifiex_process_cmdresp+0x40c/0x510 [mwifiex]
[<ffffffbffc13b8f4>] mwifiex_main_process+0x4a4/0xb00 [mwifiex]
[<ffffffbffc13bf84>] mwifiex_main_work_queue+0x34/0x40 [mwifiex]

Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/init.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 756948385b60..2ada202c72ec 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -670,8 +670,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)

mwifiex_clean_auto_tdls(priv);
mwifiex_abort_cac(priv);
- mwifiex_clean_txrx(priv);
- mwifiex_delete_bss_prio_tbl(priv);
+ mwifiex_free_priv(priv);
}
}

--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:28

by Brian Norris

[permalink] [raw]
Subject: [PATCH 03/11] mwifiex: Don't release cmd_pending_q_lock while iterating

From: Douglas Anderson <[email protected]>

Just like in the previous patch ("mwifiex: Don't release
tx_ba_stream_tbl_lock while iterating"), in
mwifiex_cancel_all_pending_cmd() we were itearting over a list protected
by a spinlock. Again, it is not safe to release the spinlock while
iterating. Don't do it.

Luckily in this case there should be no need to release the spinlock.
This is evidenced by:

1. The only function called while the spinlock was released was
mwifiex_recycle_cmd_node()
2. Aside from atomic functions (which are safe to call), the only
function called by mwifiex_recycle_cmd_node() was
mwifiex_insert_cmd_to_free_q().
3. It can be seen in mwifiex_cancel_pending_scan_cmd() that it's OK to
call mwifiex_insert_cmd_to_free_q() while holding a different
spinlock (scan_pending_q_lock), so in general holding a spinlock
should be OK.
4. It doesn't appear that mwifiex_insert_cmd_to_free_q() has any
interaction with the cmd_pending_q_lock

No known bugs are fixed with this change, but as with other similar
changes this could fix random list corruption.

Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/cmdevt.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 0c3b217247b1..5fd6c53d7b06 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -1056,12 +1056,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->cmd_pending_q, list) {
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);

if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
mwifiex_recycle_cmd_node(adapter, cmd_node);
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
}
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-12 16:42:29

by Brian Norris

[permalink] [raw]
Subject: [PATCH 04/11] mwifiex: Add locking to mwifiex_11n_delba

From: Douglas Anderson <[email protected]>

The mwifiex_11n_delba() function walked the rx_reorder_tbl_ptr without
holding the lock, which was an obvious violation.

Grab the lock.

NOTE: we hold the lock while calling mwifiex_send_delba(). There's also
several callers in 11n_rxreorder.c that hold the lock and the comments
in the struct sound just like very other list/lock pair -- as if the
lock should definitely be help for all operations like this.

Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Brian Norris <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/11n.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c
index c75b6abf16a0..16c77c27f1b6 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n.c
@@ -653,11 +653,13 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
{
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+ unsigned long flags;

+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
if (list_empty(&priv->rx_reorder_tbl_ptr)) {
dev_dbg(priv->adapter->dev,
"mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n");
- return;
+ goto exit;
}

list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
@@ -666,9 +668,11 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
"Send delba to tid=%d, %pM\n",
tid, rx_reor_tbl_ptr->ta);
mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0);
- return;
+ goto exit;
}
}
+exit:
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
}

/*
--
2.13.0.rc2.291.g57267f2277-goog

2017-05-19 06:02:51

by Kalle Valo

[permalink] [raw]
Subject: Re: [01/11] mwifiex: fixup error cases in mwifiex_add_virtual_intf()

Brian Norris <[email protected]> wrote:
> If we fail to add an interface in mwifiex_add_virtual_intf(), we might
> hit a BUG_ON() in the networking code, because we didn't tear things
> down properly. Among the problems:
>
> (a) when failing to allocate workqueues, we fail to unregister the
> netdev before calling free_netdev()
> (b) even if we do try to unregister the netdev, we're still holding the
> rtnl lock, so the device never properly unregistered; we'll be at
> state NETREG_UNREGISTERING, and then hit free_netdev()'s:
> BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
> (c) we're allocating some dependent resources (e.g., DFS workqueues)
> after we've registered the interface; this may or may not cause
> problems, but it's good practice to allocate these before registering
> (d) we're not even trying to unwind anything when mwifiex_send_cmd() or
> mwifiex_sta_init_cmd() fail
>
> To fix these issues, let's:
>
> * add a stacked set of error handling labels, to keep error handling
> consistent and properly ordered (resolving (a) and (d))
> * move the workqueue allocations before the registration (to resolve
> (c); also resolves (b) by avoiding error cases where we have to
> unregister)
>
> [Incidentally, it's pretty easy to interrupt the alloc_workqueue() in,
> e.g., the following:
>
> iw phy phy0 interface add mlan0 type station
>
> by sending it SIGTERM.]
>
> This bugfix covers commits like commit 7d652034d1a0 ("mwifiex: channel
> switch support for mwifiex"), but parts of this bug exist all the way
> back to the introduction of dynamic interface handling in commit
> 93a1df48d224 ("mwifiex: add cfg80211 handlers add/del_virtual_intf").
>
> Cc: <[email protected]>
> Signed-off-by: Brian Norris <[email protected]>

11 patches applied to wireless-drivers-next.git, thanks.

8535107aa4ef mwifiex: fixup error cases in mwifiex_add_virtual_intf()
e0b636e5ee15 mwifiex: Don't release tx_ba_stream_tbl_lock while iterating
90ad0be83676 mwifiex: Don't release cmd_pending_q_lock while iterating
09bdb6500551 mwifiex: Add locking to mwifiex_11n_delba
0f13acf0c612 mwifiex: don't drop lock between list-retrieval / list-deletion
6eb2d002d4ea mwifiex: don't leak stashed beacon buffer on reset
bc69ca391eff mwifiex: remove useless 'mwifiex_lock'
7170862738dc mwifiex: remove redundant 'adapter' check in mwifiex_adapter_cleanup
7ade530e7384 mwifiex: 11h: drop unnecessary check for '!priv'
fa4651e12ae8 mwifiex: pcie: remove useless pdev check
68efd0386988 mwifiex: pcie: stop setting/clearing 'surprise_removed'

--
https://patchwork.kernel.org/patch/9724599/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2017-05-17 04:02:51

by Xinming Hu

[permalink] [raw]
Subject: RE: [PATCH 01/11] mwifiex: fixup error cases in mwifiex_add_virtual_intf()

SGksDQoNClRoaXMgcGF0Y2ggc2VyaWFscyBsb29rcyBmaW5lLCB0aGFua3MuDQoNCj4gLS0tLS1P
cmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogbGludXgtd2lyZWxlc3Mtb3duZXJAdmdlci5r
ZXJuZWwub3JnDQo+IFttYWlsdG86bGludXgtd2lyZWxlc3Mtb3duZXJAdmdlci5rZXJuZWwub3Jn
XSBPbiBCZWhhbGYgT2YgQnJpYW4gTm9ycmlzDQo+IFNlbnQ6IDIwMTfE6jXUwjEzyNUgMDo0Mg0K
PiBUbzogR2FuYXBhdGhpIEJoYXQ7IE5pc2hhbnQgU2FybXVrYWRhbQ0KPiBDYzogbGludXgta2Vy
bmVsQHZnZXIua2VybmVsLm9yZzsgRG1pdHJ5IFRvcm9raG92OyBBbWl0a3VtYXIgS2Fyd2FyOyBL
YWxsZQ0KPiBWYWxvOyBsaW51eC13aXJlbGVzc0B2Z2VyLmtlcm5lbC5vcmc7IERvdWcgQW5kZXJz
b247IEJyaWFuIE5vcnJpcw0KPiBTdWJqZWN0OiBbUEFUQ0ggMDEvMTFdIG13aWZpZXg6IGZpeHVw
IGVycm9yIGNhc2VzIGluIG13aWZpZXhfYWRkX3ZpcnR1YWxfaW50ZigpDQo+IA0KPiBJZiB3ZSBm
YWlsIHRvIGFkZCBhbiBpbnRlcmZhY2UgaW4gbXdpZmlleF9hZGRfdmlydHVhbF9pbnRmKCksIHdl
IG1pZ2h0IGhpdCBhDQo+IEJVR19PTigpIGluIHRoZSBuZXR3b3JraW5nIGNvZGUsIGJlY2F1c2Ug
d2UgZGlkbid0IHRlYXIgdGhpbmdzIGRvd24NCj4gcHJvcGVybHkuIEFtb25nIHRoZSBwcm9ibGVt
czoNCj4gDQo+ICAoYSkgd2hlbiBmYWlsaW5nIHRvIGFsbG9jYXRlIHdvcmtxdWV1ZXMsIHdlIGZh
aWwgdG8gdW5yZWdpc3RlciB0aGUNCj4gICAgICBuZXRkZXYgYmVmb3JlIGNhbGxpbmcgZnJlZV9u
ZXRkZXYoKQ0KPiAgKGIpIGV2ZW4gaWYgd2UgZG8gdHJ5IHRvIHVucmVnaXN0ZXIgdGhlIG5ldGRl
diwgd2UncmUgc3RpbGwgaG9sZGluZyB0aGUNCj4gICAgICBydG5sIGxvY2ssIHNvIHRoZSBkZXZp
Y2UgbmV2ZXIgcHJvcGVybHkgdW5yZWdpc3RlcmVkOyB3ZSdsbCBiZSBhdA0KPiAgICAgIHN0YXRl
IE5FVFJFR19VTlJFR0lTVEVSSU5HLCBhbmQgdGhlbiBoaXQgZnJlZV9uZXRkZXYoKSdzOg0KPiAJ
QlVHX09OKGRldi0+cmVnX3N0YXRlICE9IE5FVFJFR19VTlJFR0lTVEVSRUQpOw0KPiAgKGMpIHdl
J3JlIGFsbG9jYXRpbmcgc29tZSBkZXBlbmRlbnQgcmVzb3VyY2VzIChlLmcuLCBERlMgd29ya3F1
ZXVlcykNCj4gICAgICBhZnRlciB3ZSd2ZSByZWdpc3RlcmVkIHRoZSBpbnRlcmZhY2U7IHRoaXMg
bWF5IG9yIG1heSBub3QgY2F1c2UNCj4gICAgICBwcm9ibGVtcywgYnV0IGl0J3MgZ29vZCBwcmFj
dGljZSB0byBhbGxvY2F0ZSB0aGVzZSBiZWZvcmUgcmVnaXN0ZXJpbmcNCj4gIChkKSB3ZSdyZSBu
b3QgZXZlbiB0cnlpbmcgdG8gdW53aW5kIGFueXRoaW5nIHdoZW4gbXdpZmlleF9zZW5kX2NtZCgp
IG9yDQo+ICAgICAgbXdpZmlleF9zdGFfaW5pdF9jbWQoKSBmYWlsDQo+IA0KPiBUbyBmaXggdGhl
c2UgaXNzdWVzLCBsZXQnczoNCj4gDQo+ICAqIGFkZCBhIHN0YWNrZWQgc2V0IG9mIGVycm9yIGhh
bmRsaW5nIGxhYmVscywgdG8ga2VlcCBlcnJvciBoYW5kbGluZw0KPiAgICBjb25zaXN0ZW50IGFu
ZCBwcm9wZXJseSBvcmRlcmVkIChyZXNvbHZpbmcgKGEpIGFuZCAoZCkpDQo+ICAqIG1vdmUgdGhl
IHdvcmtxdWV1ZSBhbGxvY2F0aW9ucyBiZWZvcmUgdGhlIHJlZ2lzdHJhdGlvbiAodG8gcmVzb2x2
ZQ0KPiAgICAoYyk7IGFsc28gcmVzb2x2ZXMgKGIpIGJ5IGF2b2lkaW5nIGVycm9yIGNhc2VzIHdo
ZXJlIHdlIGhhdmUgdG8NCj4gICAgdW5yZWdpc3RlcikNCj4gDQo+IFtJbmNpZGVudGFsbHksIGl0
J3MgcHJldHR5IGVhc3kgdG8gaW50ZXJydXB0IHRoZSBhbGxvY193b3JrcXVldWUoKSBpbiwgZS5n
LiwgdGhlDQo+IGZvbGxvd2luZzoNCj4gDQo+ICAgaXcgcGh5IHBoeTAgaW50ZXJmYWNlIGFkZCBt
bGFuMCB0eXBlIHN0YXRpb24NCj4gDQo+IGJ5IHNlbmRpbmcgaXQgU0lHVEVSTS5dDQo+IA0KPiBU
aGlzIGJ1Z2ZpeCBjb3ZlcnMgY29tbWl0cyBsaWtlIGNvbW1pdCA3ZDY1MjAzNGQxYTAgKCJtd2lm
aWV4OiBjaGFubmVsDQo+IHN3aXRjaCBzdXBwb3J0IGZvciBtd2lmaWV4IiksIGJ1dCBwYXJ0cyBv
ZiB0aGlzIGJ1ZyBleGlzdCBhbGwgdGhlIHdheSBiYWNrIHRvIHRoZQ0KPiBpbnRyb2R1Y3Rpb24g
b2YgZHluYW1pYyBpbnRlcmZhY2UgaGFuZGxpbmcgaW4gY29tbWl0DQo+IDkzYTFkZjQ4ZDIyNCAo
Im13aWZpZXg6IGFkZCBjZmc4MDIxMSBoYW5kbGVycyBhZGQvZGVsX3ZpcnR1YWxfaW50ZiIpLg0K
PiANCj4gQ2M6IDxzdGFibGVAdmdlci5rZXJuZWwub3JnPg0KPiBTaWduZWQtb2ZmLWJ5OiBCcmlh
biBOb3JyaXMgPGJyaWFubm9ycmlzQGNocm9taXVtLm9yZz4NCj4gLS0tDQo+ICBkcml2ZXJzL25l
dC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvY2ZnODAyMTEuYyB8IDcxDQo+ICsrKysrKysrKysr
Ky0tLS0tLS0tLS0tLS0NCj4gIDEgZmlsZSBjaGFuZ2VkLCAzNSBpbnNlcnRpb25zKCspLCAzNiBk
ZWxldGlvbnMoLSkNCj4gDQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2
ZWxsL213aWZpZXgvY2ZnODAyMTEuYw0KPiBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL21hcnZlbGwv
bXdpZmlleC9jZmc4MDIxMS5jDQo+IGluZGV4IDdlYzA2YmYxMzQxMy4uMDI1YmMwNmExOWQ2IDEw
MDY0NA0KPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvY2ZnODAy
MTEuYw0KPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9tYXJ2ZWxsL213aWZpZXgvY2ZnODAy
MTEuYw0KPiBAQCAtMjk2NCwxMCArMjk2NCw4IEBAIHN0cnVjdCB3aXJlbGVzc19kZXYNCj4gKm13
aWZpZXhfYWRkX3ZpcnR1YWxfaW50ZihzdHJ1Y3Qgd2lwaHkgKndpcGh5LA0KPiAgCWlmICghZGV2
KSB7DQo+ICAJCW13aWZpZXhfZGJnKGFkYXB0ZXIsIEVSUk9SLA0KPiAgCQkJICAgICJubyBtZW1v
cnkgYXZhaWxhYmxlIGZvciBuZXRkZXZpY2VcbiIpOw0KPiAtCQltZW1zZXQoJnByaXYtPndkZXYs
IDAsIHNpemVvZihwcml2LT53ZGV2KSk7DQo+IC0JCXByaXYtPndkZXYuaWZ0eXBlID0gTkw4MDIx
MV9JRlRZUEVfVU5TUEVDSUZJRUQ7DQo+IC0JCXByaXYtPmJzc19tb2RlID0gTkw4MDIxMV9JRlRZ
UEVfVU5TUEVDSUZJRUQ7DQo+IC0JCXJldHVybiBFUlJfUFRSKC1FTk9NRU0pOw0KPiArCQlyZXQg
PSAtRU5PTUVNOw0KPiArCQlnb3RvIGVycl9hbGxvY19uZXRkZXY7DQo+ICAJfQ0KPiANCj4gIAlt
d2lmaWV4X2luaXRfcHJpdl9wYXJhbXMocHJpdiwgZGV2KTsNCj4gQEAgLTI5NzYsMTEgKzI5NzQs
MTEgQEAgc3RydWN0IHdpcmVsZXNzX2Rldg0KPiAqbXdpZmlleF9hZGRfdmlydHVhbF9pbnRmKHN0
cnVjdCB3aXBoeSAqd2lwaHksDQo+ICAJcmV0ID0gbXdpZmlleF9zZW5kX2NtZChwcml2LCBIb3N0
Q21kX0NNRF9TRVRfQlNTX01PREUsDQo+ICAJCQkgICAgICAgSG9zdENtZF9BQ1RfR0VOX1NFVCwg
MCwgTlVMTCwgdHJ1ZSk7DQo+ICAJaWYgKHJldCkNCj4gLQkJcmV0dXJuIEVSUl9QVFIocmV0KTsN
Cj4gKwkJZ290byBlcnJfc2V0X2Jzc19tb2RlOw0KPiANCj4gIAlyZXQgPSBtd2lmaWV4X3N0YV9p
bml0X2NtZChwcml2LCBmYWxzZSwgZmFsc2UpOw0KPiAgCWlmIChyZXQpDQo+IC0JCXJldHVybiBF
UlJfUFRSKHJldCk7DQo+ICsJCWdvdG8gZXJyX3N0YV9pbml0Ow0KPiANCj4gIAltd2lmaWV4X3Nl
dHVwX2h0X2NhcHMoJndpcGh5LT5iYW5kc1tOTDgwMjExX0JBTkRfMkdIWl0tPmh0X2NhcCwNCj4g
cHJpdik7DQo+ICAJaWYgKGFkYXB0ZXItPmlzX2h3XzExYWNfY2FwYWJsZSkNCj4gQEAgLTMwMTEs
MzEgKzMwMDksMTQgQEAgc3RydWN0IHdpcmVsZXNzX2Rldg0KPiAqbXdpZmlleF9hZGRfdmlydHVh
bF9pbnRmKHN0cnVjdCB3aXBoeSAqd2lwaHksDQo+IA0KPiAgCVNFVF9ORVRERVZfREVWKGRldiwg
YWRhcHRlci0+ZGV2KTsNCj4gDQo+IC0JLyogUmVnaXN0ZXIgbmV0d29yayBkZXZpY2UgKi8NCj4g
LQlpZiAocmVnaXN0ZXJfbmV0ZGV2aWNlKGRldikpIHsNCj4gLQkJbXdpZmlleF9kYmcoYWRhcHRl
ciwgRVJST1IsDQo+IC0JCQkgICAgImNhbm5vdCByZWdpc3RlciB2aXJ0dWFsIG5ldHdvcmsgZGV2
aWNlXG4iKTsNCj4gLQkJZnJlZV9uZXRkZXYoZGV2KTsNCj4gLQkJcHJpdi0+YnNzX21vZGUgPSBO
TDgwMjExX0lGVFlQRV9VTlNQRUNJRklFRDsNCj4gLQkJcHJpdi0+bmV0ZGV2ID0gTlVMTDsNCj4g
LQkJbWVtc2V0KCZwcml2LT53ZGV2LCAwLCBzaXplb2YocHJpdi0+d2RldikpOw0KPiAtCQlwcml2
LT53ZGV2LmlmdHlwZSA9IE5MODAyMTFfSUZUWVBFX1VOU1BFQ0lGSUVEOw0KPiAtCQlyZXR1cm4g
RVJSX1BUUigtRUZBVUxUKTsNCj4gLQl9DQo+IC0NCj4gIAlwcml2LT5kZnNfY2FjX3dvcmtxdWV1
ZSA9IGFsbG9jX3dvcmtxdWV1ZSgiTVdJRklFWF9ERlNfQ0FDJXMiLA0KPiAgCQkJCQkJICBXUV9I
SUdIUFJJIHwNCj4gIAkJCQkJCSAgV1FfTUVNX1JFQ0xBSU0gfA0KPiAgCQkJCQkJICBXUV9VTkJP
VU5ELCAxLCBuYW1lKTsNCj4gIAlpZiAoIXByaXYtPmRmc19jYWNfd29ya3F1ZXVlKSB7DQo+IC0J
CW13aWZpZXhfZGJnKGFkYXB0ZXIsIEVSUk9SLA0KPiAtCQkJICAgICJjYW5ub3QgcmVnaXN0ZXIg
dmlydHVhbCBuZXR3b3JrIGRldmljZVxuIik7DQo+IC0JCWZyZWVfbmV0ZGV2KGRldik7DQo+IC0J
CXByaXYtPmJzc19tb2RlID0gTkw4MDIxMV9JRlRZUEVfVU5TUEVDSUZJRUQ7DQo+IC0JCXByaXYt
Pm5ldGRldiA9IE5VTEw7DQo+IC0JCW1lbXNldCgmcHJpdi0+d2RldiwgMCwgc2l6ZW9mKHByaXYt
PndkZXYpKTsNCj4gLQkJcHJpdi0+d2Rldi5pZnR5cGUgPSBOTDgwMjExX0lGVFlQRV9VTlNQRUNJ
RklFRDsNCj4gLQkJcmV0dXJuIEVSUl9QVFIoLUVOT01FTSk7DQo+ICsJCW13aWZpZXhfZGJnKGFk
YXB0ZXIsIEVSUk9SLCAiY2Fubm90IGFsbG9jIERGUyBDQUMgcXVldWVcbiIpOw0KPiArCQlyZXQg
PSAtRU5PTUVNOw0KPiArCQlnb3RvIGVycl9hbGxvY19jYWM7DQo+ICAJfQ0KPiANCj4gIAlJTklU
X0RFTEFZRURfV09SSygmcHJpdi0+ZGZzX2NhY193b3JrLA0KPiBtd2lmaWV4X2Rmc19jYWNfd29y
a19xdWV1ZSk7IEBAIC0zMDQ0LDE2ICszMDI1LDkgQEAgc3RydWN0IHdpcmVsZXNzX2Rldg0KPiAq
bXdpZmlleF9hZGRfdmlydHVhbF9pbnRmKHN0cnVjdCB3aXBoeSAqd2lwaHksDQo+ICAJCQkJCQkg
ICAgICBXUV9ISUdIUFJJIHwgV1FfVU5CT1VORCB8DQo+ICAJCQkJCQkgICAgICBXUV9NRU1fUkVD
TEFJTSwgMSwgbmFtZSk7DQo+ICAJaWYgKCFwcml2LT5kZnNfY2hhbl9zd193b3JrcXVldWUpIHsN
Cj4gLQkJbXdpZmlleF9kYmcoYWRhcHRlciwgRVJST1IsDQo+IC0JCQkgICAgImNhbm5vdCByZWdp
c3RlciB2aXJ0dWFsIG5ldHdvcmsgZGV2aWNlXG4iKTsNCj4gLQkJZnJlZV9uZXRkZXYoZGV2KTsN
Cj4gLQkJcHJpdi0+YnNzX21vZGUgPSBOTDgwMjExX0lGVFlQRV9VTlNQRUNJRklFRDsNCj4gLQkJ
cHJpdi0+bmV0ZGV2ID0gTlVMTDsNCj4gLQkJbWVtc2V0KCZwcml2LT53ZGV2LCAwLCBzaXplb2Yo
cHJpdi0+d2RldikpOw0KPiAtCQlwcml2LT53ZGV2LmlmdHlwZSA9IE5MODAyMTFfSUZUWVBFX1VO
U1BFQ0lGSUVEOw0KPiAtCQlkZXN0cm95X3dvcmtxdWV1ZShwcml2LT5kZnNfY2FjX3dvcmtxdWV1
ZSk7DQo+IC0JCXByaXYtPmRmc19jYWNfd29ya3F1ZXVlID0gTlVMTDsNCj4gLQkJcmV0dXJuIEVS
Ul9QVFIoLUVOT01FTSk7DQo+ICsJCW13aWZpZXhfZGJnKGFkYXB0ZXIsIEVSUk9SLCAiY2Fubm90
IGFsbG9jIERGUyBjaGFubmVsIHN3DQo+IHF1ZXVlXG4iKTsNCj4gKwkJcmV0ID0gLUVOT01FTTsN
Cj4gKwkJZ290byBlcnJfYWxsb2NfY2hzdzsNCj4gIAl9DQo+IA0KPiAgCUlOSVRfREVMQVlFRF9X
T1JLKCZwcml2LT5kZnNfY2hhbl9zd193b3JrLA0KPiBAQCAtMzA2MSw2ICszMDM1LDEzIEBAIHN0
cnVjdCB3aXJlbGVzc19kZXYNCj4gKm13aWZpZXhfYWRkX3ZpcnR1YWxfaW50ZihzdHJ1Y3Qgd2lw
aHkgKndpcGh5LA0KPiANCj4gIAlzZW1hX2luaXQoJnByaXYtPmFzeW5jX3NlbSwgMSk7DQo+IA0K
PiArCS8qIFJlZ2lzdGVyIG5ldHdvcmsgZGV2aWNlICovDQo+ICsJaWYgKHJlZ2lzdGVyX25ldGRl
dmljZShkZXYpKSB7DQo+ICsJCW13aWZpZXhfZGJnKGFkYXB0ZXIsIEVSUk9SLCAiY2Fubm90IHJl
Z2lzdGVyIG5ldHdvcmsgZGV2aWNlXG4iKTsNCj4gKwkJcmV0ID0gLUVGQVVMVDsNCj4gKwkJZ290
byBlcnJfcmVnX25ldGRldjsNCj4gKwl9DQo+ICsNCj4gIAltd2lmaWV4X2RiZyhhZGFwdGVyLCBJ
TkZPLA0KPiAgCQkgICAgImluZm86ICVzOiBNYXJ2ZWxsIDgwMi4xMSBBZGFwdGVyXG4iLCBkZXYt
Pm5hbWUpOw0KPiANCj4gQEAgLTMwODEsMTEgKzMwNjIsMjkgQEAgc3RydWN0IHdpcmVsZXNzX2Rl
dg0KPiAqbXdpZmlleF9hZGRfdmlydHVhbF9pbnRmKHN0cnVjdCB3aXBoeSAqd2lwaHksDQo+ICAJ
CWFkYXB0ZXItPmN1cnJfaWZhY2VfY29tYi5wMnBfaW50ZisrOw0KPiAgCQlicmVhazsNCj4gIAlk
ZWZhdWx0Og0KPiArCQkvKiBUaGlzIHNob3VsZCBiZSBkZWFkIGNvZGU7IGNoZWNrZWQgYWJvdmUg
Ki8NCj4gIAkJbXdpZmlleF9kYmcoYWRhcHRlciwgRVJST1IsICJ0eXBlIG5vdCBzdXBwb3J0ZWRc
biIpOw0KPiAgCQlyZXR1cm4gRVJSX1BUUigtRUlOVkFMKTsNCj4gIAl9DQo+IA0KPiAgCXJldHVy
biAmcHJpdi0+d2RldjsNCj4gKw0KPiArZXJyX3JlZ19uZXRkZXY6DQo+ICsJZGVzdHJveV93b3Jr
cXVldWUocHJpdi0+ZGZzX2NoYW5fc3dfd29ya3F1ZXVlKTsNCj4gKwlwcml2LT5kZnNfY2hhbl9z
d193b3JrcXVldWUgPSBOVUxMOw0KPiArZXJyX2FsbG9jX2Noc3c6DQo+ICsJZGVzdHJveV93b3Jr
cXVldWUocHJpdi0+ZGZzX2NhY193b3JrcXVldWUpOw0KPiArCXByaXYtPmRmc19jYWNfd29ya3F1
ZXVlID0gTlVMTDsNCj4gK2Vycl9hbGxvY19jYWM6DQo+ICsJZnJlZV9uZXRkZXYoZGV2KTsNCj4g
Kwlwcml2LT5uZXRkZXYgPSBOVUxMOw0KPiArZXJyX3N0YV9pbml0Og0KPiArZXJyX3NldF9ic3Nf
bW9kZToNCj4gK2Vycl9hbGxvY19uZXRkZXY6DQo+ICsJbWVtc2V0KCZwcml2LT53ZGV2LCAwLCBz
aXplb2YocHJpdi0+d2RldikpOw0KPiArCXByaXYtPndkZXYuaWZ0eXBlID0gTkw4MDIxMV9JRlRZ
UEVfVU5TUEVDSUZJRUQ7DQo+ICsJcHJpdi0+YnNzX21vZGUgPSBOTDgwMjExX0lGVFlQRV9VTlNQ
RUNJRklFRDsNCj4gKwlyZXR1cm4gRVJSX1BUUihyZXQpOw0KPiAgfQ0KPiAgRVhQT1JUX1NZTUJP
TF9HUEwobXdpZmlleF9hZGRfdmlydHVhbF9pbnRmKTsNCj4gDQoNClJlZ2FyZHMsDQpTaW1vbg0K
DQo+IC0tDQo+IDIuMTMuMC5yYzIuMjkxLmc1NzI2N2YyMjc3LWdvb2cNCg0K