Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Oct 2017 13:13:38 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r324278 - in head/sys/compat/linuxkpi/common: include/linux src
Message-ID:  <201710041313.v94DDcNC045759@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201710041313.v94DDcNC045759>