summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhaad <haad@NetBSD.org>2008-11-30 00:17:07 +0000
committerhaad <haad@NetBSD.org>2008-11-30 00:17:07 +0000
commite51aea320a2f8f7d3ee4cf3a514b763e1afe7d98 (patch)
tree9ae94e778dfea49f2ec1f8c6293f2737b4ed7113
parent82b58f55f09a1f72110cce8384381003ddfe82ca (diff)
Fix two race conditions in proplib library. In prop_dictionary and prop_number
there was small window in which was entry left in rb tree with reference count 0 which lead to rb tree coruption when another thread picked this up before it was released. Add 2 new members to the prop_object_t which are used for locking/unlocking rb tree guard mutex. Ok by joerg@, core@, thorpej@
-rw-r--r--common/lib/libprop/prop_dictionary.c27
-rw-r--r--common/lib/libprop/prop_number.c21
-rw-r--r--common/lib/libprop/prop_object.c38
-rw-r--r--common/lib/libprop/prop_object_impl.h4
4 files changed, 77 insertions, 13 deletions
diff --git a/common/lib/libprop/prop_dictionary.c b/common/lib/libprop/prop_dictionary.c
index 7827555fe61..4ccec00e65c 100644
--- a/common/lib/libprop/prop_dictionary.c
+++ b/common/lib/libprop/prop_dictionary.c
@@ -1,4 +1,4 @@
-/* $NetBSD: prop_dictionary.c,v 1.32 2008/08/03 04:00:12 thorpej Exp $ */
+/* $NetBSD: prop_dictionary.c,v 1.33 2008/11/30 00:17:07 haad Exp $ */
/*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@@ -125,6 +125,9 @@ static prop_object_t
static prop_object_t
_prop_dictionary_get(prop_dictionary_t, const char *, bool);
+static void _prop_dictionary_lock(void);
+static void _prop_dictionary_unlock(void);
+
static const struct _prop_object_type _prop_object_type_dictionary = {
.pot_type = PROP_TYPE_DICTIONARY,
.pot_free = _prop_dictionary_free,
@@ -132,6 +135,8 @@ static const struct _prop_object_type _prop_object_type_dictionary = {
.pot_extern = _prop_dictionary_externalize,
.pot_equals = _prop_dictionary_equals,
.pot_equals_finish = _prop_dictionary_equals_finish,
+ .pot_lock = _prop_dictionary_lock,
+ .pot_unlock = _prop_dictionary_unlock,
};
static _prop_object_free_rv_t
@@ -220,10 +225,7 @@ _prop_dict_keysym_free(prop_stack_t stack, prop_object_t *obj)
{
prop_dictionary_keysym_t pdk = *obj;
- _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex);
_prop_rb_tree_remove_node(&_prop_dict_keysym_tree, &pdk->pdk_link);
- _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
-
_prop_dict_keysym_put(pdk);
return _PROP_OBJECT_FREE_DONE;
@@ -381,11 +383,26 @@ _prop_dictionary_free(prop_stack_t stack, prop_object_t *obj)
--pd->pd_count;
pdk = pd->pd_array[pd->pd_count].pde_key;
_PROP_ASSERT(pdk != NULL);
+
prop_object_release(pdk);
+
*obj = po;
return (_PROP_OBJECT_FREE_RECURSE);
}
+
+static void
+_prop_dictionary_lock(void)
+{
+ _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex);
+}
+
+static void
+_prop_dictionary_unlock(void)
+{
+ _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
+}
+
static void
_prop_dictionary_emergency_free(prop_object_t obj)
{
@@ -1075,7 +1092,9 @@ _prop_dictionary_remove(prop_dictionary_t pd, struct _prop_dict_entry *pde,
pd->pd_count--;
pd->pd_version++;
+
prop_object_release(pdk);
+
prop_object_release(po);
}
diff --git a/common/lib/libprop/prop_number.c b/common/lib/libprop/prop_number.c
index 7adf808b36f..9f5cb18c742 100644
--- a/common/lib/libprop/prop_number.c
+++ b/common/lib/libprop/prop_number.c
@@ -1,4 +1,4 @@
-/* $NetBSD: prop_number.c,v 1.19 2008/08/03 04:00:12 thorpej Exp $ */
+/* $NetBSD: prop_number.c,v 1.20 2008/11/30 00:17:07 haad Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -74,11 +74,16 @@ static _prop_object_equals_rv_t
void **, void **,
prop_object_t *, prop_object_t *);
+static void _prop_number_lock(void);
+static void _prop_number_unlock(void);
+
static const struct _prop_object_type _prop_object_type_number = {
.pot_type = PROP_TYPE_NUMBER,
.pot_free = _prop_number_free,
.pot_extern = _prop_number_externalize,
.pot_equals = _prop_number_equals,
+ .pot_lock = _prop_number_lock,
+ .pot_unlock = _prop_number_unlock,
};
#define prop_object_is_number(x) \
@@ -152,15 +157,25 @@ _prop_number_free(prop_stack_t stack, prop_object_t *obj)
{
prop_number_t pn = *obj;
- _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
_prop_rb_tree_remove_node(&_prop_number_tree, &pn->pn_link);
- _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
_PROP_POOL_PUT(_prop_number_pool, pn);
return (_PROP_OBJECT_FREE_DONE);
}
+static void
+_prop_number_lock()
+{
+ _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
+}
+
+static void
+_prop_number_unlock()
+{
+ _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
+}
+
static bool
_prop_number_externalize(struct _prop_object_externalize_context *ctx,
void *v)
diff --git a/common/lib/libprop/prop_object.c b/common/lib/libprop/prop_object.c
index b0b0eb9133d..5740a5d72b4 100644
--- a/common/lib/libprop/prop_object.c
+++ b/common/lib/libprop/prop_object.c
@@ -1,4 +1,4 @@
-/* $NetBSD: prop_object.c,v 1.22 2008/08/03 04:00:12 thorpej Exp $ */
+/* $NetBSD: prop_object.c,v 1.23 2008/11/30 00:17:07 haad Exp $ */
/*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@@ -1019,6 +1019,7 @@ static void
prop_object_release_emergency(prop_object_t obj)
{
struct _prop_object *po;
+ void (*unlock)(void);
prop_object_t parent = NULL;
uint32_t ocnt;
@@ -1026,19 +1027,34 @@ prop_object_release_emergency(prop_object_t obj)
po = obj;
_PROP_ASSERT(obj);
+ if (po->po_type->pot_lock != NULL)
+ po->po_type->pot_lock();
+
+ /* Save pointerto unlock function */
+ unlock = po->po_type->pot_unlock;
+
_PROP_REFCNT_LOCK();
ocnt = po->po_refcnt--;
_PROP_REFCNT_UNLOCK();
_PROP_ASSERT(ocnt != 0);
- if (ocnt != 1)
+ if (ocnt != 1) {
+ if (unlock != NULL)
+ unlock();
break;
-
+ }
+
_PROP_ASSERT(po->po_type);
if ((po->po_type->pot_free)(NULL, &obj) ==
- _PROP_OBJECT_FREE_DONE)
+ _PROP_OBJECT_FREE_DONE) {
+ if (unlock != NULL)
+ unlock();
break;
+ }
+ if (unlock != NULL)
+ unlock();
+
parent = po;
_PROP_REFCNT_LOCK();
++po->po_refcnt;
@@ -1062,6 +1078,7 @@ prop_object_release(prop_object_t obj)
{
struct _prop_object *po;
struct _prop_stack stack;
+ void (*unlock)(void);
int ret;
uint32_t ocnt;
@@ -1072,6 +1089,12 @@ prop_object_release(prop_object_t obj)
po = obj;
_PROP_ASSERT(obj);
+ if (po->po_type->pot_lock != NULL)
+ po->po_type->pot_lock();
+
+ /* Save pointer to object unlock function */
+ unlock = po->po_type->pot_unlock;
+
_PROP_REFCNT_LOCK();
ocnt = po->po_refcnt--;
_PROP_REFCNT_UNLOCK();
@@ -1079,11 +1102,16 @@ prop_object_release(prop_object_t obj)
_PROP_ASSERT(ocnt != 0);
if (ocnt != 1) {
ret = 0;
+ if (unlock != NULL)
+ unlock();
break;
}
-
+
ret = (po->po_type->pot_free)(&stack, &obj);
+ if (unlock != NULL)
+ unlock();
+
if (ret == _PROP_OBJECT_FREE_DONE)
break;
diff --git a/common/lib/libprop/prop_object_impl.h b/common/lib/libprop/prop_object_impl.h
index 8190b26df0f..d58ec4a3a29 100644
--- a/common/lib/libprop/prop_object_impl.h
+++ b/common/lib/libprop/prop_object_impl.h
@@ -1,4 +1,4 @@
-/* $NetBSD: prop_object_impl.h,v 1.27 2008/08/03 04:00:12 thorpej Exp $ */
+/* $NetBSD: prop_object_impl.h,v 1.28 2008/11/30 00:17:07 haad Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -211,6 +211,8 @@ struct _prop_object_type {
* _PROP_OBJECT_EQUALS_RECURSE
*/
void (*pot_equals_finish)(prop_object_t, prop_object_t);
+ void (*pot_lock)(void);
+ void (*pot_unlock)(void);
};
struct _prop_object {