aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>2016-03-10 06:03:18 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-03-10 15:33:16 -0500
commit0d67e0fa1664ad6aaba0552e170608bafb4b6196 (patch)
tree28987f5570ca421359271c4bc22b3dca3f90dd66
parent7781203416ffc4e731619f8a8b93a37599a8f502 (diff)
device property: fix for a case of use-after-free
In device_remove_property_set(), the secondary fwnode needs to be cleared before the pset is freed. This fixes a use-after-free when a property set is providing the primary fwnode. As a result of the fix, the primary fwnode may end up containing ERR_PTR(-ENODEV), so also adding checks for it to the property handling code. Reported-by: John Youn <John.Youn@synopsys.com> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/property.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c
index a163f2c59aa3..76628a7b45f1 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -218,7 +218,8 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
218 bool ret; 218 bool ret;
219 219
220 ret = __fwnode_property_present(fwnode, propname); 220 ret = __fwnode_property_present(fwnode, propname);
221 if (ret == false && fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) 221 if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
222 !IS_ERR_OR_NULL(fwnode->secondary))
222 ret = __fwnode_property_present(fwnode->secondary, propname); 223 ret = __fwnode_property_present(fwnode->secondary, propname);
223 return ret; 224 return ret;
224} 225}
@@ -423,7 +424,8 @@ EXPORT_SYMBOL_GPL(device_property_match_string);
423 int _ret_; \ 424 int _ret_; \
424 _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \ 425 _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \
425 _val_, _nval_); \ 426 _val_, _nval_); \
426 if (_ret_ == -EINVAL && _fwnode_ && !IS_ERR_OR_NULL(_fwnode_->secondary)) \ 427 if (_ret_ == -EINVAL && !IS_ERR_OR_NULL(_fwnode_) && \
428 !IS_ERR_OR_NULL(_fwnode_->secondary)) \
427 _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \ 429 _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \
428 _proptype_, _val_, _nval_); \ 430 _proptype_, _val_, _nval_); \
429 _ret_; \ 431 _ret_; \
@@ -593,7 +595,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
593 int ret; 595 int ret;
594 596
595 ret = __fwnode_property_read_string_array(fwnode, propname, val, nval); 597 ret = __fwnode_property_read_string_array(fwnode, propname, val, nval);
596 if (ret == -EINVAL && fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) 598 if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
599 !IS_ERR_OR_NULL(fwnode->secondary))
597 ret = __fwnode_property_read_string_array(fwnode->secondary, 600 ret = __fwnode_property_read_string_array(fwnode->secondary,
598 propname, val, nval); 601 propname, val, nval);
599 return ret; 602 return ret;
@@ -621,7 +624,8 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
621 int ret; 624 int ret;
622 625
623 ret = __fwnode_property_read_string(fwnode, propname, val); 626 ret = __fwnode_property_read_string(fwnode, propname, val);
624 if (ret == -EINVAL && fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) 627 if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
628 !IS_ERR_OR_NULL(fwnode->secondary))
625 ret = __fwnode_property_read_string(fwnode->secondary, 629 ret = __fwnode_property_read_string(fwnode->secondary,
626 propname, val); 630 propname, val);
627 return ret; 631 return ret;
@@ -820,11 +824,16 @@ void device_remove_property_set(struct device *dev)
820 * the pset. If there is no real firmware node (ACPI/DT) primary 824 * the pset. If there is no real firmware node (ACPI/DT) primary
821 * will hold the pset. 825 * will hold the pset.
822 */ 826 */
823 if (!is_pset_node(fwnode)) 827 if (is_pset_node(fwnode)) {
824 fwnode = fwnode->secondary; 828 set_primary_fwnode(dev, NULL);
825 if (!IS_ERR(fwnode) && is_pset_node(fwnode))
826 pset_free_set(to_pset_node(fwnode)); 829 pset_free_set(to_pset_node(fwnode));
827 set_secondary_fwnode(dev, NULL); 830 } else {
831 fwnode = fwnode->secondary;
832 if (!IS_ERR(fwnode) && is_pset_node(fwnode)) {
833 set_secondary_fwnode(dev, NULL);
834 pset_free_set(to_pset_node(fwnode));
835 }
836 }
828} 837}
829EXPORT_SYMBOL_GPL(device_remove_property_set); 838EXPORT_SYMBOL_GPL(device_remove_property_set);
830 839