svn commit: r324278 - in head/sys/compat/linuxkpi/common: include/linux src
Hans Petter Selasky
hselasky at FreeBSD.org
Wed Oct 4 13:13:40 UTC 2017
Author: hselasky
Date: Wed Oct 4 13:13:38 2017
New Revision: 324278
URL: https://svnweb.freebsd.org/changeset/base/324278
Log:
Make sure the timer belonging to the delayed work in the LinuxKPI
gets drained before invoking the work function. Else the timer
mutex may still be in use which can lead to use-after-free situations,
because the work function might free the work structure before returning.
MFC after: 1 week
Sponsored by: Mellanox Technologies
Modified:
head/sys/compat/linuxkpi/common/include/linux/workqueue.h
head/sys/compat/linuxkpi/common/src/linux_work.c
Modified: head/sys/compat/linuxkpi/common/include/linux/workqueue.h
==============================================================================
--- head/sys/compat/linuxkpi/common/include/linux/workqueue.h Wed Oct 4 12:58:30 2017 (r324277)
+++ head/sys/compat/linuxkpi/common/include/linux/workqueue.h Wed Oct 4 13:13:38 2017 (r324278)
@@ -215,6 +215,7 @@ extern struct workqueue_struct *system_power_efficient
extern void linux_init_delayed_work(struct delayed_work *, work_func_t);
extern void linux_work_fn(void *, int);
+extern void linux_delayed_work_fn(void *, int);
extern struct workqueue_struct *linux_create_workqueue_common(const char *, int);
extern void linux_destroy_workqueue(struct workqueue_struct *);
extern bool linux_queue_work_on(int cpu, struct workqueue_struct *, struct work_struct *);
Modified: head/sys/compat/linuxkpi/common/src/linux_work.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_work.c Wed Oct 4 12:58:30 2017 (r324277)
+++ head/sys/compat/linuxkpi/common/src/linux_work.c Wed Oct 4 13:13:38 2017 (r324278)
@@ -260,6 +260,23 @@ done:
WQ_EXEC_UNLOCK(wq);
}
+void
+linux_delayed_work_fn(void *context, int pending)
+{
+ struct delayed_work *dwork = context;
+
+ /*
+ * Make sure the timer belonging to the delayed work gets
+ * drained before invoking the work function. Else the timer
+ * mutex may still be in use which can lead to use-after-free
+ * situations, because the work function might free the work
+ * structure before returning.
+ */
+ callout_drain(&dwork->timer.callout);
+
+ linux_work_fn(&dwork->work, pending);
+}
+
static void
linux_delayed_work_timer_fn(void *arg)
{
@@ -550,7 +567,8 @@ void
linux_init_delayed_work(struct delayed_work *dwork, work_func_t func)
{
memset(dwork, 0, sizeof(*dwork));
- INIT_WORK(&dwork->work, func);
+ dwork->work.func = func;
+ TASK_INIT(&dwork->work.work_task, 0, linux_delayed_work_fn, dwork);
mtx_init(&dwork->timer.mtx, spin_lock_name("lkpi-dwork"), NULL,
MTX_DEF | MTX_NOWITNESS);
callout_init_mtx(&dwork->timer.callout, &dwork->timer.mtx, 0);
More information about the svn-src-head
mailing list