Skip to content

Commit 8fc1cbe

Browse files
eddiejamesEddie James
authored and
GitHub Enterprise
committed
net: ncsi: Prevent use-after-free in workqueues (torvalds#318)
Workqueues can run after being canceled, so prevent further scheduling. Signed-off-by: Eddie James <[email protected]> Co-authored-by: Eddie James <[email protected]>
1 parent 0c2a7bd commit 8fc1cbe

File tree

3 files changed

+23
-11
lines changed

3 files changed

+23
-11
lines changed

drivers/net/ethernet/faraday/ftgmac100.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ struct ftgmac100 {
109109
/* Misc */
110110
bool need_mac_restart;
111111
bool is_aspeed;
112+
bool shutdown;
112113
};
113114

114115
static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
@@ -1110,7 +1111,7 @@ ftgmac100_set_ringparam(struct net_device *netdev,
11101111

11111112
priv->new_rx_q_entries = ering->rx_pending;
11121113
priv->new_tx_q_entries = ering->tx_pending;
1113-
if (netif_running(netdev))
1114+
if (netif_running(netdev) && !priv->shutdown)
11141115
schedule_work(&priv->reset_task);
11151116

11161117
return 0;
@@ -1188,7 +1189,8 @@ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
11881189
netdev_warn(netdev,
11891190
"AHB bus error ! Resetting chip.\n");
11901191
iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
1191-
schedule_work(&priv->reset_task);
1192+
if (!priv->shutdown)
1193+
schedule_work(&priv->reset_task);
11921194
return IRQ_HANDLED;
11931195
}
11941196

@@ -1600,7 +1602,8 @@ static void ftgmac100_tx_timeout(struct net_device *netdev, unsigned int txqueue
16001602
iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
16011603

16021604
/* Do the reset outside of interrupt context */
1603-
schedule_work(&priv->reset_task);
1605+
if (!priv->shutdown)
1606+
schedule_work(&priv->reset_task);
16041607
}
16051608

16061609
static int ftgmac100_set_features(struct net_device *netdev,
@@ -2032,6 +2035,7 @@ static int ftgmac100_remove(struct platform_device *pdev)
20322035
/* There's a small chance the reset task will have been re-queued,
20332036
* during stop, make sure it's gone before we free the structure.
20342037
*/
2038+
priv->shutdown = true;
20352039
cancel_work_sync(&priv->reset_task);
20362040

20372041
ftgmac100_phy_disconnect(netdev);

net/ncsi/internal.h

+1
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ struct ncsi_dev_priv {
318318
#define NCSI_DEV_HWA 2 /* Enabled HW arbitration */
319319
#define NCSI_DEV_RESHUFFLE 4
320320
#define NCSI_DEV_RESET 8 /* Reset state of NC */
321+
#define NCSI_DEV_SHUTDOWN 16
321322
unsigned int gma_flag; /* OEM GMA flag */
322323
spinlock_t lock; /* Protect the NCSI device */
323324
unsigned int package_probe_id;/* Current ID during probe */

net/ncsi/ncsi-manage.c

+15-8
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ void ncsi_free_request(struct ncsi_request *nr)
410410
driven = !!(nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN);
411411
spin_unlock_irqrestore(&ndp->lock, flags);
412412

413-
if (driven && cmd && --ndp->pending_req_num == 0)
413+
if (driven && cmd && --ndp->pending_req_num == 0 && !(ndp->flags & NCSI_DEV_SHUTDOWN))
414414
schedule_work(&ndp->work);
415415

416416
/* Release command and response */
@@ -1055,7 +1055,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
10551055
ret = ncsi_gma_handler(&nca, nc->version.mf_id);
10561056
#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
10571057

1058-
if (ret < 0)
1058+
if (ret < 0 && !(ndp->flags & NCSI_DEV_SHUTDOWN))
10591059
schedule_work(&ndp->work);
10601060

10611061
break;
@@ -1079,7 +1079,8 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
10791079
ret = clear_one_vid(ndp, nc, &nca);
10801080
if (ret) {
10811081
nd->state = ncsi_dev_state_config_svf;
1082-
schedule_work(&ndp->work);
1082+
if (!(ndp->flags & NCSI_DEV_SHUTDOWN))
1083+
schedule_work(&ndp->work);
10831084
break;
10841085
}
10851086
/* Repeat */
@@ -1089,7 +1090,8 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
10891090
ret = set_one_vid(ndp, nc, &nca);
10901091
if (ret) {
10911092
nd->state = ncsi_dev_state_config_ev;
1092-
schedule_work(&ndp->work);
1093+
if (!(ndp->flags & NCSI_DEV_SHUTDOWN))
1094+
schedule_work(&ndp->work);
10931095
break;
10941096
}
10951097
/* Repeat */
@@ -1396,15 +1398,17 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
13961398
if (!ndp->active_package) {
13971399
/* No response */
13981400
nd->state = ncsi_dev_state_probe_dp;
1399-
schedule_work(&ndp->work);
1401+
if (!(ndp->flags & NCSI_DEV_SHUTDOWN))
1402+
schedule_work(&ndp->work);
14001403
break;
14011404
}
14021405
nd->state = ncsi_dev_state_probe_cis;
14031406
if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) &&
14041407
ndp->mlx_multi_host)
14051408
nd->state = ncsi_dev_state_probe_mlx_gma;
14061409

1407-
schedule_work(&ndp->work);
1410+
if (!(ndp->flags & NCSI_DEV_SHUTDOWN))
1411+
schedule_work(&ndp->work);
14081412
break;
14091413
#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
14101414
case ncsi_dev_state_probe_mlx_gma:
@@ -1825,7 +1829,8 @@ int ncsi_start_dev(struct ncsi_dev *nd)
18251829
if (!(ndp->flags & NCSI_DEV_PROBED)) {
18261830
ndp->package_probe_id = 0;
18271831
nd->state = ncsi_dev_state_probe;
1828-
schedule_work(&ndp->work);
1832+
if (!(ndp->flags & NCSI_DEV_SHUTDOWN))
1833+
schedule_work(&ndp->work);
18291834
return 0;
18301835
}
18311836

@@ -1947,7 +1952,8 @@ int ncsi_reset_dev(struct ncsi_dev *nd)
19471952
spin_unlock_irqrestore(&ndp->lock, flags);
19481953

19491954
nd->state = ncsi_dev_state_suspend;
1950-
schedule_work(&ndp->work);
1955+
if (!(ndp->flags & NCSI_DEV_SHUTDOWN))
1956+
schedule_work(&ndp->work);
19511957
return 0;
19521958
}
19531959

@@ -1966,6 +1972,7 @@ void ncsi_unregister_dev(struct ncsi_dev *nd)
19661972
list_del_rcu(&ndp->node);
19671973
spin_unlock_irqrestore(&ncsi_dev_lock, flags);
19681974

1975+
ndp->flags |= NCSI_DEV_SHUTDOWN;
19691976
cancel_work_sync(&ndp->work);
19701977

19711978
kfree(ndp);

0 commit comments

Comments
 (0)