lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1466759333-4703-4-git-send-email-chris@chris-wilson.co.uk>
Date:	Fri, 24 Jun 2016 10:08:47 +0100
From:	Chris Wilson <chris@...is-wilson.co.uk>
To:	linux-kernel@...r.kernel.org
Cc:	Chris Wilson <chris@...is-wilson.co.uk>,
	Sumit Semwal <sumit.semwal@...aro.org>,
	Shuah Khan <shuahkh@....samsung.com>,
	Tejun Heo <tj@...nel.org>,
	Daniel Vetter <daniel.vetter@...ll.ch>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Ingo Molnar <mingo@...nel.org>,
	Kees Cook <keescook@...omium.org>,
	Thomas Gleixner <tglx@...utronix.de>,
	"Paul E. McKenney" <paulmck@...ux.vnet.ibm.com>,
	Dan Williams <dan.j.williams@...el.com>,
	Andrey Ryabinin <aryabinin@...tuozzo.com>,
	Davidlohr Bueso <dave@...olabs.net>,
	Nikolay Aleksandrov <nikolay@...ulusnetworks.com>,
	"David S. Miller" <davem@...emloft.net>,
	"Peter Zijlstra (Intel)" <peterz@...radead.org>,
	Rasmus Villemoes <linux@...musvillemoes.dk>,
	Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
	Dmitry Vyukov <dvyukov@...gle.com>,
	Alexander Potapenko <glider@...gle.com>,
	linux-media@...r.kernel.org, dri-devel@...ts.freedesktop.org,
	linaro-mm-sig@...ts.linaro.org
Subject: [PATCH 3/9] async: Extend kfence to allow struct embedding

Provide a kfence_init() function for use for embedding the kfence into a
parent structure. kfence_init() takes an optional function pointer argument
should the caller wish to be notified when the kfence is complete. This is
useful for allowing the kfences to drive other state machinery.

Signed-off-by: Chris Wilson <chris@...is-wilson.co.uk>
Cc: Sumit Semwal <sumit.semwal@...aro.org>
Cc: Shuah Khan <shuahkh@....samsung.com>
Cc: Tejun Heo <tj@...nel.org>
Cc: Daniel Vetter <daniel.vetter@...ll.ch>
Cc: Andrew Morton <akpm@...ux-foundation.org>
Cc: Ingo Molnar <mingo@...nel.org>
Cc: Kees Cook <keescook@...omium.org>
Cc: Thomas Gleixner <tglx@...utronix.de>
Cc: "Paul E. McKenney" <paulmck@...ux.vnet.ibm.com>
Cc: Dan Williams <dan.j.williams@...el.com>
Cc: Andrey Ryabinin <aryabinin@...tuozzo.com>
Cc: Davidlohr Bueso <dave@...olabs.net>
Cc: Nikolay Aleksandrov <nikolay@...ulusnetworks.com>
Cc: "David S. Miller" <davem@...emloft.net>
Cc: "Peter Zijlstra (Intel)" <peterz@...radead.org>
Cc: Rasmus Villemoes <linux@...musvillemoes.dk>
Cc: Andy Shevchenko <andriy.shevchenko@...ux.intel.com>
Cc: Dmitry Vyukov <dvyukov@...gle.com>
Cc: Alexander Potapenko <glider@...gle.com>
Cc: linux-kernel@...r.kernel.org
Cc: linux-media@...r.kernel.org
Cc: dri-devel@...ts.freedesktop.org
Cc: linaro-mm-sig@...ts.linaro.org
---
 include/linux/kfence.h |  5 ++++
 kernel/async.c         | 52 ++++++++++++++++++++++++++++++++++++----
 lib/test-kfence.c      | 64 +++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 109 insertions(+), 12 deletions(-)

diff --git a/include/linux/kfence.h b/include/linux/kfence.h
index 82eba8aacd02..82096bfafaa1 100644
--- a/include/linux/kfence.h
+++ b/include/linux/kfence.h
@@ -38,4 +38,9 @@ static inline bool kfence_complete(struct kfence *fence)
 }
 extern void kfence_put(struct kfence *fence);
 
+typedef void (*kfence_notify_t)(struct kfence *);
+#define __kfence_call __attribute__((aligned(4)))
+
+extern void kfence_init(struct kfence *fence, kfence_notify_t fn);
+
 #endif /* _KFENCE_H_ */
diff --git a/kernel/async.c b/kernel/async.c
index d0bcb7cc4884..db22b890711e 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -134,7 +134,17 @@ static atomic_t entry_count;
  *
  * The fence starts off pending a single signal. Once you have finished
  * setting up the fence, use kfence_signal() to allow it to wait upon
- * its event sources.
+ * its event sources. To embed a kfence within another struct, use
+ *
+ * 	kfence_init()
+ *
+ * This can also be used to receive a callback when the kfence is completed
+ * (pending signal count hits 0).  The callback is also called when the fence
+ * is released (the reference count hits 0, and the fence will be complete).
+ * Note that since the kfence is embedded inside another, its initial reference
+ * must not be dropped unless a callback is provided, or the kfence is the
+ * first member in the parent, and the parent was allocated by kmalloc (i.e.
+ * valid to be freed by kfree()).
  *
  * Use
  *
@@ -151,7 +161,11 @@ static void kfence_free(struct kref *kref)
 
 	WARN_ON(atomic_read(&fence->pending) > 0);
 
-	kfree(fence);
+	if (fence->flags) {
+		kfence_notify_t fn = (kfence_notify_t)fence->flags;
+		fn(fence);
+	} else
+		kfree(fence);
 }
 
 /**
@@ -203,6 +217,11 @@ static void __kfence_signal(struct kfence *fence,
 	if (!atomic_dec_and_test(&fence->pending))
 		return;
 
+	if (fence->flags) {
+		kfence_notify_t fn = (kfence_notify_t)fence->flags;
+		fn(fence);
+	}
+
 	atomic_dec(&fence->pending);
 	__kfence_wake_up_all(fence, continuation);
 }
@@ -240,7 +259,7 @@ void kfence_wait(struct kfence *fence)
 }
 EXPORT_SYMBOL_GPL(kfence_wait);
 
-static void kfence_init(struct kfence *fence)
+static void __kfence_init(struct kfence *fence)
 {
 	init_waitqueue_head(&fence->wait);
 	kref_init(&fence->kref);
@@ -266,11 +285,36 @@ struct kfence *kfence_create(gfp_t gfp)
 	if (!fence)
 		return NULL;
 
-	kfence_init(fence);
+	__kfence_init(fence);
 	return fence;
 }
 EXPORT_SYMBOL_GPL(kfence_create);
 
+/**
+ * kfence_init - initialize a fence for use embedded within a struct
+ * @fence: this kfence
+ * @fn: a callback function for when the fence is complete, and when the
+ * fence is released
+ *
+ * This function initialises the @fence for use embedded within a parent
+ * structure. The optional @fn hook is called when the fence is completed
+ * (when all of its events sources have signaled their completion, i.e.
+ * pending signal count hits 0, fence_complete() however reports false as the
+ * fence is not considered complete until after the callback returns) and when
+ * the fence is subsequently released (the reference count hits 0,
+ * fence_complete() is then true). Note carefully that @fn will be called from
+ * atomic context. Also the lower 2 bits of the function pointer are used for
+ * storing flags, so the function must be aligned to at least 4 bytes - use
+ * __kfence_call as a function attribute to ensure correct alignment.
+ */
+void kfence_init(struct kfence *fence, kfence_notify_t fn)
+{
+	__kfence_init(fence);
+	BUG_ON((unsigned long)fn & KFENCE_CHECKED_BIT);
+	fence->flags = (unsigned long)fn;
+}
+EXPORT_SYMBOL_GPL(kfence_init);
+
 static int kfence_wake(wait_queue_t *wq, unsigned mode, int flags, void *key)
 {
 	list_del(&wq->task_list);
diff --git a/lib/test-kfence.c b/lib/test-kfence.c
index 1d9e4a5a2184..0604a27f68b2 100644
--- a/lib/test-kfence.c
+++ b/lib/test-kfence.c
@@ -9,9 +9,27 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 
+static int __init __test_self(struct kfence *fence)
+{
+	if (kfence_complete(fence))
+		return -EINVAL;
+
+	kfence_signal(fence);
+
+	if (!kfence_complete(fence))
+		return -EINVAL;
+
+	kfence_wait(fence);
+	if (!kfence_complete(fence))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int __init test_self(void)
 {
 	struct kfence *fence;
+	int ret;
 
 	/* Test kfence signaling and completion testing */
 	pr_debug("%s\n", __func__);
@@ -20,19 +38,43 @@ static int __init test_self(void)
 	if (!fence)
 		return -ENOMEM;
 
-	if (kfence_complete(fence))
-		return -EINVAL;
+	ret = __test_self(fence);
 
-	kfence_signal(fence);
+	kfence_put(fence);
+	return ret;
+}
 
-	if (!kfence_complete(fence))
-		return -EINVAL;
+struct test_stack {
+	struct kfence fence;
+	bool seen;
+};
 
-	kfence_wait(fence);
-	if (!kfence_complete(fence))
+static void __init __kfence_call fence_callback(struct kfence *fence)
+{
+	struct test_stack *ts = container_of(fence, typeof(*ts), fence);
+	ts->seen = true;
+}
+
+static int __init test_stack(void)
+{
+	struct test_stack ts;
+	int ret;
+
+	/* Test kfence signaling and completion testing (on stack) */
+	pr_debug("%s\n", __func__);
+
+	ts.seen = false;
+	kfence_init(&ts.fence, fence_callback);
+
+	ret = __test_self(&ts.fence);
+	if (ret < 0)
+		return ret;
+
+	if (!ts.seen) {
+		pr_err("fence callback not executed\n");
 		return -EINVAL;
+	}
 
-	kfence_put(fence);
 	return 0;
 }
 
@@ -413,6 +455,12 @@ static int __init test_kfence_init(void)
 		return ret;
 	}
 
+	ret = test_stack();
+	if (ret < 0) {
+		pr_err("stack failed\n");
+		return ret;
+	}
+
 	ret = test_dag();
 	if (ret < 0) {
 		pr_err("DAG checker failed\n");
-- 
2.8.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ