mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 14:48:57 +00:00
MFC r292254:
Properly drain callouts in the IPFW subsystem to avoid use after free panics when unloading the dummynet and IPFW modules: - The callout drain function can sleep and should not be called having a non-sleepable lock locked. Remove locks around "ipfw_dyn_uninit(0)". - Add a new "dn_gone" variable to prevent asynchronous restart of dummynet callouts when unloading the dummynet kernel module. - Call "dn_reschedule()" locked so that "dn_gone" can be set and checked atomically with regard to starting a new callout. PR: 208171 Requested by: Franco Fichtner (opnsense.org) Differential Revision: https://reviews.freebsd.org/D3855
This commit is contained in:
parent
9c89526448
commit
e2e9c7067a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/stable/10/; revision=297228
@ -619,8 +619,8 @@ dummynet_task(void *context, int pending)
|
||||
dn_drain_queue();
|
||||
}
|
||||
|
||||
DN_BH_WUNLOCK();
|
||||
dn_reschedule();
|
||||
DN_BH_WUNLOCK();
|
||||
if (q.head != NULL)
|
||||
dummynet_send(q.head);
|
||||
CURVNET_RESTORE();
|
||||
|
@ -74,6 +74,7 @@ struct schk_new_arg {
|
||||
|
||||
/*---- callout hooks. ----*/
|
||||
static struct callout dn_timeout;
|
||||
static int dn_gone;
|
||||
static struct task dn_task;
|
||||
static struct taskqueue *dn_tq = NULL;
|
||||
|
||||
@ -89,6 +90,8 @@ void
|
||||
dn_reschedule(void)
|
||||
{
|
||||
|
||||
if (dn_gone != 0)
|
||||
return;
|
||||
callout_reset_sbt(&dn_timeout, tick_sbt, 0, dummynet, NULL,
|
||||
C_HARDCLOCK | C_DIRECT_EXEC);
|
||||
}
|
||||
@ -2175,9 +2178,11 @@ ip_dn_init(void)
|
||||
static void
|
||||
ip_dn_destroy(int last)
|
||||
{
|
||||
callout_drain(&dn_timeout);
|
||||
|
||||
DN_BH_WLOCK();
|
||||
/* ensure no more callouts are started */
|
||||
dn_gone = 1;
|
||||
|
||||
/* check for last */
|
||||
if (last) {
|
||||
ND("removing last instance\n");
|
||||
ip_dn_ctl_ptr = NULL;
|
||||
@ -2186,6 +2191,8 @@ ip_dn_destroy(int last)
|
||||
|
||||
dummynet_flush();
|
||||
DN_BH_WUNLOCK();
|
||||
|
||||
callout_drain(&dn_timeout);
|
||||
taskqueue_drain(dn_tq, &dn_task);
|
||||
taskqueue_free(dn_tq);
|
||||
|
||||
|
@ -2704,12 +2704,10 @@ vnet_ipfw_uninit(const void *unused)
|
||||
V_ip_fw_ctl_ptr = NULL;
|
||||
IPFW_UH_WLOCK(chain);
|
||||
IPFW_UH_WUNLOCK(chain);
|
||||
IPFW_UH_WLOCK(chain);
|
||||
|
||||
IPFW_WLOCK(chain);
|
||||
ipfw_dyn_uninit(0); /* run the callout_drain */
|
||||
IPFW_WUNLOCK(chain);
|
||||
|
||||
IPFW_UH_WLOCK(chain);
|
||||
ipfw_destroy_tables(chain);
|
||||
reap = NULL;
|
||||
IPFW_WLOCK(chain);
|
||||
|
Loading…
Reference in New Issue
Block a user