Pull driver core fix from Greg Kroah-Hartman: "Here's a single patch for the firmware core that resolves a reported oops in the firmware core that people have been hitting." * tag 'driver-core-3.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: firmware loader: fix use-after-free by double abort
Unified · Split
| @@ -450,8 +450,18 @@ static void fw_load_abort(struct firmware_priv *fw_priv) · 449 unmodified lines | ||
| 450 | 450 | { |
| 451 | 451 | struct firmware_buf *buf = fw_priv->buf; |
| 452 | 452 | |
| 453 | + /* | |
| 454 | + * There is a small window in which user can write to 'loading' | |
| 455 | + * between loading done and disappearance of 'loading' | |
| 456 | + */ | |
| 457 | + if (test_bit(FW_STATUS_DONE, &buf->status)) | |
| 458 | + return; | |
| 459 | + | |
| 453 | 460 | set_bit(FW_STATUS_ABORT, &buf->status); |
| 454 | 461 | complete_all(&buf->completion); |
| 462 | + | |
| 463 | + /* avoid user action after loading abort */ | |
| 464 | + fw_priv->buf = NULL; | |
| 455 | 465 | } |
| 456 | 466 | |
| 457 | 467 | #define is_fw_load_aborted(buf) \ |
| @@ -528,7 +538,12 @@ static ssize_t firmware_loading_show(struct device *dev, · 70 unmodified lines | ||
| 528 | 538 | struct device_attribute *attr, char *buf) |
| 529 | 539 | { |
| 530 | 540 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
| 531 | − int loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status); | |
| 541 | + int loading = 0; | |
| 542 | + | |
| 543 | + mutex_lock(&fw_lock); | |
| 544 | + if (fw_priv->buf) | |
| 545 | + loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status); | |
| 546 | + mutex_unlock(&fw_lock); | |
| 532 | 547 | |
| 533 | 548 | return sprintf(buf, "%d\n", loading); |
| 534 | 549 | } |
| @@ -570,12 +585,12 @@ static ssize_t firmware_loading_store(struct device *dev, · 35 unmodified lines | ||
| 570 | 585 | const char *buf, size_t count) |
| 571 | 586 | { |
| 572 | 587 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
| 573 | − struct firmware_buf *fw_buf = fw_priv->buf; | |
| 588 | + struct firmware_buf *fw_buf; | |
| 574 | 589 | int loading = simple_strtol(buf, NULL, 10); |
| 575 | 590 | int i; |
| 576 | 591 | |
| 577 | 592 | mutex_lock(&fw_lock); |
| 578 | − | |
| 593 | + fw_buf = fw_priv->buf; | |
| 579 | 594 | if (!fw_buf) |
| 580 | 595 | goto out; |
| 581 | 596 | |
| @@ -777,10 +792,6 @@ static void firmware_class_timeout_work(struct work_struct *work) · 195 unmodified lines | ||
| 777 | 792 | struct firmware_priv, timeout_work.work); |
| 778 | 793 | |
| 779 | 794 | mutex_lock(&fw_lock); |
| 780 | − if (test_bit(FW_STATUS_DONE, &(fw_priv->buf->status))) { | |
| 781 | − mutex_unlock(&fw_lock); | |
| 782 | − return; | |
| 783 | − } | |
| 784 | 795 | fw_load_abort(fw_priv); |
| 785 | 796 | mutex_unlock(&fw_lock); |
| 786 | 797 | } |
| @@ -861,8 +872,6 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, · 74 unmodified lines | ||
| 861 | 872 | |
| 862 | 873 | cancel_delayed_work_sync(&fw_priv->timeout_work); |
| 863 | 874 | |
| 864 | − fw_priv->buf = NULL; | |
| 865 | − | |
| 866 | 875 | device_remove_file(f_dev, &dev_attr_loading); |
| 867 | 876 | err_del_bin_attr: |
| 868 | 877 | device_remove_bin_file(f_dev, &firmware_attr_data); |