diff options
| author | haad <haad@NetBSD.org> | 2008-11-30 00:17:07 +0000 |
|---|---|---|
| committer | haad <haad@NetBSD.org> | 2008-11-30 00:17:07 +0000 |
| commit | e51aea320a2f8f7d3ee4cf3a514b763e1afe7d98 (patch) | |
| tree | 9ae94e778dfea49f2ec1f8c6293f2737b4ed7113 | |
| parent | 82b58f55f09a1f72110cce8384381003ddfe82ca (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.c | 27 | ||||
| -rw-r--r-- | common/lib/libprop/prop_number.c | 21 | ||||
| -rw-r--r-- | common/lib/libprop/prop_object.c | 38 | ||||
| -rw-r--r-- | common/lib/libprop/prop_object_impl.h | 4 |
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 { |
