diff mbox series

scsi_dh_rdac: avoid crash during rescan

Message ID 20191111104522.99531-1-hare@suse.de (mailing list archive)
State Changes Requested
Headers show
Series scsi_dh_rdac: avoid crash during rescan | expand

Commit Message

Hannes Reinecke Nov. 11, 2019, 10:45 a.m. UTC
During rescanning the device might already have been removed, so
we should drop the BUG_ON and just ignore the non-existing device.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/scsi/device_handler/scsi_dh_rdac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

Bart Van Assche Nov. 11, 2019, 4:07 p.m. UTC | #1
On 11/11/19 2:45 AM, Hannes Reinecke wrote:
> During rescanning the device might already have been removed, so
> we should drop the BUG_ON and just ignore the non-existing device.
> 
> Signed-off-by: Hannes Reinecke <hare@suse.de>
> ---
>   drivers/scsi/device_handler/scsi_dh_rdac.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
> index 5efc959493ec..33a71df5ee59 100644
> --- a/drivers/scsi/device_handler/scsi_dh_rdac.c
> +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
> @@ -424,8 +424,8 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
>   		rcu_read_lock();
>   		list_for_each_entry_rcu(tmp, &h->ctlr->dh_list, node) {
>   			/* h->sdev should always be valid */
> -			BUG_ON(!tmp->sdev);
> -			tmp->sdev->access_state = access_state;
> +			if (tmp->sdev) {
> +				tmp->sdev->access_state = access_state;
>   		}
>   		rcu_read_unlock();
>   		err = SCSI_DH_OK;

Since rdac_bus_detach() may clear h->sdev concurrently with the above 
code I think READ_ONCE() is needed to make the above code safe.

Has it been considered to change the kfree() call in rdac_bus_detach() 
into a kfree_rcu() call? I think otherwise the above 
list_for_each_entry_rcu() loop may trigger a use-after-free.

Thanks,

Bart.
Hannes Reinecke Nov. 12, 2019, 4:25 p.m. UTC | #2
On 11/11/19 5:07 PM, Bart Van Assche wrote:
> On 11/11/19 2:45 AM, Hannes Reinecke wrote:
>> During rescanning the device might already have been removed, so
>> we should drop the BUG_ON and just ignore the non-existing device.
>>
>> Signed-off-by: Hannes Reinecke <hare@suse.de>
>> ---
>>   drivers/scsi/device_handler/scsi_dh_rdac.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c
>> b/drivers/scsi/device_handler/scsi_dh_rdac.c
>> index 5efc959493ec..33a71df5ee59 100644
>> --- a/drivers/scsi/device_handler/scsi_dh_rdac.c
>> +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
>> @@ -424,8 +424,8 @@ static int check_ownership(struct scsi_device
>> *sdev, struct rdac_dh_data *h)
>>           rcu_read_lock();
>>           list_for_each_entry_rcu(tmp, &h->ctlr->dh_list, node) {
>>               /* h->sdev should always be valid */
>> -            BUG_ON(!tmp->sdev);
>> -            tmp->sdev->access_state = access_state;
>> +            if (tmp->sdev) {
>> +                tmp->sdev->access_state = access_state;
>>           }
>>           rcu_read_unlock();
>>           err = SCSI_DH_OK;
> 
> Since rdac_bus_detach() may clear h->sdev concurrently with the above
> code I think READ_ONCE() is needed to make the above code safe.
> 
> Has it been considered to change the kfree() call in rdac_bus_detach()
> into a kfree_rcu() call? I think otherwise the above
> list_for_each_entry_rcu() loop may trigger a use-after-free.
> 
Good point. I'll have a look.

Cheers,

Hannes
Christoph Hellwig Nov. 14, 2019, 5:01 p.m. UTC | #3
On Mon, Nov 11, 2019 at 11:45:22AM +0100, Hannes Reinecke wrote:
> During rescanning the device might already have been removed, so
> we should drop the BUG_ON and just ignore the non-existing device.

The device is also added to the list before sdev is set, which is rather
silly, so that might be worth fixing as well.
diff mbox series

Patch

diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 5efc959493ec..33a71df5ee59 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -424,8 +424,8 @@  static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 		rcu_read_lock();
 		list_for_each_entry_rcu(tmp, &h->ctlr->dh_list, node) {
 			/* h->sdev should always be valid */
-			BUG_ON(!tmp->sdev);
-			tmp->sdev->access_state = access_state;
+			if (tmp->sdev) {
+				tmp->sdev->access_state = access_state;
 		}
 		rcu_read_unlock();
 		err = SCSI_DH_OK;