diff options
author | Justin T. Gibbs <[email protected]> | 2015-04-02 22:59:15 +1100 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-04-28 16:25:44 -0700 |
commit | 6ebebaceb1091142b81430291c610d79b6a3073e (patch) | |
tree | 70197ad52e7d910f4a860dcfc1d475aa5d073efc /module/zfs/dsl_prop.c | |
parent | 0c66c32d1d8b64a261cceb5f50a9e86777c5d0b2 (diff) |
Illumos 5531 - NULL pointer dereference in dsl_prop_get_ds()
5531 NULL pointer dereference in dsl_prop_get_ds()
Author: Justin T. Gibbs <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: Dan McDonald <[email protected]>
Reviewed by: George Wilson <[email protected]>
Reviewed by: Bayard Bell <[email protected]>
Approved by: Robert Mustacchi <[email protected]>
References:
https://www.illumos.org/issues/5531
https://github.com/illumos/illumos-gate/commit/e57a022
Ported-by: Chris Dunlop <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module/zfs/dsl_prop.c')
-rw-r--r-- | module/zfs/dsl_prop.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 4c0e57990..69bcd190f 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -441,9 +441,31 @@ dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) cbr = list_next(&dd->dd_prop_cbs, cbr)) { uint64_t value; + /* + * Callback entries do not have holds on their datasets + * so that datasets with registered callbacks are still + * eligible for eviction. Unlike operations on callbacks + * for a single dataset, we are performing a recursive + * descent of related datasets and the calling context + * for this iteration only has a dataset hold on the root. + * Without a hold, the callback's pointer to the dataset + * could be invalidated by eviction at any time. + * + * Use dsl_dataset_try_add_ref() to verify that the + * dataset has not begun eviction processing and to + * prevent eviction from occurring for the duration + * of the callback. If the hold attempt fails, this + * object is already being evicted and the callback can + * be safely ignored. + */ + if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) + continue; + if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname, sizeof (value), 1, &value, NULL) == 0) cbr->cbr_func(cbr->cbr_arg, value); + + dsl_dataset_rele(cbr->cbr_ds, FTAG); } mutex_exit(&dd->dd_lock); @@ -496,19 +518,28 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, mutex_enter(&dd->dd_lock); for (cbr = list_head(&dd->dd_prop_cbs); cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { - uint64_t propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj; + uint64_t propobj; - if (strcmp(cbr->cbr_propname, propname) != 0) + /* + * cbr->cbf_ds may be invalidated due to eviction, + * requiring the use of dsl_dataset_try_add_ref(). + * See comment block in dsl_prop_notify_all_cb() + * for details. + */ + if (strcmp(cbr->cbr_propname, propname) != 0 || + !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) continue; + propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj; + /* - * If the property is set on this ds, then it is not - * inherited here; don't call the callback. + * If the property is not set on this ds, then it is + * inherited here; call the callback. */ - if (propobj && 0 == zap_contains(mos, propobj, propname)) - continue; + if (propobj == 0 || zap_contains(mos, propobj, propname) != 0) + cbr->cbr_func(cbr->cbr_arg, value); - cbr->cbr_func(cbr->cbr_arg, value); + dsl_dataset_rele(cbr->cbr_ds, FTAG); } mutex_exit(&dd->dd_lock); |