⬢ DragonFlyBSD Kernel Audit
DF-5681 / fix.diff
← back to finding ↓ download raw
--- a/sys/libprop/prop_number.c
+++ b/sys/libprop/prop_number.c
@@ -164,10 +164,27 @@ static const rb_tree_ops_t _prop_number_rb_tree_ops = {
 static struct rb_tree _prop_number_tree;
 _PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex)
 
+static int	_prop_number_init(void);
+
 /* ARGSUSED */
 static _prop_object_free_rv_t
 _prop_number_free(prop_stack_t stack, prop_object_t *obj)
 {
@@ -176,6 +193,23 @@ _prop_number_free(prop_stack_t stack, prop_object_t *obj)
 
 _PROP_ONCE_DECL(_prop_number_init_once)
 
+/*
+ * Complete the lazy initialization single-threaded at the same SYSINIT
+ * point that already creates the number objcache pool
+ * (_PROP_POOL_INIT, prop_object_impl.h:273-281 — SI_SUB_PROP).  The
+ * kernel flavor of _PROP_ONCE_RUN (prop_object_impl.h:302-303) is a
+ * cmpset-once with no completion barrier: a CPU that loses the cmpset
+ * proceeds immediately and can reach lockmgr()/_prop_rb_tree_find()
+ * while the winner is still inside _prop_number_init() — lockinit()
+ * then wipes the loser's acquisition (kern_lock.c:1300-1307) and the
+ * tree's rbt_ops may still be NULL (prop_rb.c:90-93).  Any first use
+ * necessarily comes after SI_SUB_PROP because the objcache pool the
+ * alloc path needs is itself created at SI_SUB_PROP, so this bootstrap
+ * closes the window without adding a spin/wait to the hot path.
+ */
+static void
+_prop_number_bootstrap(void *unused __unused)
+{
+	_PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init);
+}
+
+SYSINIT(prop_number, SI_SUB_PROP, SI_ORDER_ANY,
+	(sysinit_cfunc_t)_prop_number_bootstrap, NULL);
+
 static int
 _prop_number_init(void)
 {