⬢ DragonFlyBSD Kernel Audit
DF-4329 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/include/linux/rcupdate.h
+++ b/sys/dev/drm/include/linux/rcupdate.h
@@ -22,6 +22,10 @@
 
 #include <asm/barrier.h>
 
+#include <sys/rcu.h>		/* DragonFly's real RCU implementation */
+
 #include <linux/rcutree.h>
 
-static inline void
-rcu_read_lock(void)
-{
-	preempt_disable();
-}
+/*
+ * Delegate the read side to DragonFly's native RCU, which tracks
+ * readers so synchronize_rcu() below can actually wait for them.
+ */
+#define rcu_read_lock()		rcu_read_lock_native()
+#define rcu_read_unlock()	rcu_read_unlock_native()
@@ -90,9 +94,14 @@
 extern void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *));
 
 #define rcu_access_pointer(p)	((typeof(*p) *)READ_ONCE(p))
 
-#define synchronize_rcu()
-#define cond_synchronize_rcu(x)  cpu_mfence()
-#define get_state_synchronize_rcu()	0
+/*
+ * The empty synchronize_rcu() silently broke every lifetime protocol
+ * in the drm/i915 port that relies on grace periods (e.g. the i915
+ * request-object SLAB_TYPESAFE_BY_RCU reuse protocol in
+ * i915_request.c / i915_request.h).  Map them onto the native
+ * implementation.  (Namespaced to avoid colliding with the native
+ * prototypes.)
+ */
+#define synchronize_rcu()			synchronize_rcu_native()
+#define cond_synchronize_rcu(x)			do { synchronize_rcu_native(); (void)(x); } while (0)
+#define get_state_synchronize_rcu()		get_state_synchronize_rcu_native()
 
 #endif  /* _LINUX_RCUPDATE_H_ */
--- a/sys/dev/drm/include/linux/dma-fence.h
+++ b/sys/dev/drm/include/linux/dma-fence.h
@@ -95,11 +95,17 @@ struct dma_fence {
 static inline struct dma_fence *
 dma_fence_get_rcu(struct dma_fence *fence)
 {
 	if (fence)
-		kref_get(&fence->refcount);
+		/*
+		 * The _rcu variant is used by lockless readers that may
+		 * race the fence's release: an unconditional increment
+		 * RESURRECTS a freed fence (0 -> 1) and corrupts
+		 * whatever now owns that memory.  Upstream semantics:
+		 * refuse unless the refcount is live.
+		 */
+		if (!kref_get_unless_zero(&fence->refcount))
+			return NULL;
 	return fence;
 }