RE: [PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-02-02 Thread Paul Durrant
> -Original Message-
> From: Roger Pau Monné 
> Sent: 02 February 2021 16:29
> To: Paul Durrant 
> Cc: xen-de...@lists.xenproject.org; linux-bl...@vger.kernel.org; 
> linux-kernel@vger.kernel.org; Paul
> Durrant ; Konrad Rzeszutek Wilk 
> ; Jens Axboe
> ; Dongli Zhang 
> Subject: Re: [PATCH v2] xen-blkback: fix compatibility bug with single page 
> rings
> 
> On Thu, Jan 28, 2021 at 01:04:41PM +, Paul Durrant wrote:
> > From: Paul Durrant 
> >
> > Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid
> > inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
> > behaviour of xen-blkback when connecting to a frontend was:
> >
> > - read 'ring-page-order'
> > - if not present then expect a single page ring specified by 'ring-ref'
> > - else expect a ring specified by 'ring-refX' where X is between 0 and
> >   1 << ring-page-order
> >
> > This was correct behaviour, but was broken by the afforementioned commit to
> > become:
> >
> > - read 'ring-page-order'
> > - if not present then expect a single page ring (i.e. ring-page-order = 0)
> > - expect a ring specified by 'ring-refX' where X is between 0 and
> >   1 << ring-page-order
> > - if that didn't work then see if there's a single page ring specified by
> >   'ring-ref'
> >
> > This incorrect behaviour works most of the time but fails when a frontend
> > that sets 'ring-page-order' is unloaded and replaced by one that does not
> > because, instead of reading 'ring-ref', xen-blkback will read the stale
> > 'ring-ref0' left around by the previous frontend will try to map the wrong
> > grant reference.
> >
> > This patch restores the original behaviour.
> >
> > Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid 
> > inconsistent xenstore 'ring-page-
> order' set by malicious blkfront")
> > Signed-off-by: Paul Durrant 
> > ---
> > Cc: Konrad Rzeszutek Wilk 
> > Cc: "Roger Pau Monné" 
> > Cc: Jens Axboe 
> > Cc: Dongli Zhang 
> >
> > v2:
> >  - Remove now-spurious error path special-case when nr_grefs == 1
> > ---
> >  drivers/block/xen-blkback/common.h |  1 +
> >  drivers/block/xen-blkback/xenbus.c | 38 +-
> >  2 files changed, 17 insertions(+), 22 deletions(-)
> >
> > diff --git a/drivers/block/xen-blkback/common.h 
> > b/drivers/block/xen-blkback/common.h
> > index b0c71d3a81a0..524a79f10de6 100644
> > --- a/drivers/block/xen-blkback/common.h
> > +++ b/drivers/block/xen-blkback/common.h
> > @@ -313,6 +313,7 @@ struct xen_blkif {
> >
> > struct work_struct  free_work;
> > unsigned intnr_ring_pages;
> > +   boolmulti_ref;
> 
> You seem to have used spaces between the type and the variable name
> here, while neighbors also use hard tabs.
> 

Oops. Xen vs. Linux coding style :-( I'll send a v3 with the whitespace fixed.

> The rest LGTM:
> 
> Reviewed-by: Roger Pau Monné 
> 
> We should have forbidden the usage of ring-page-order = 0 and we could
> have avoided having to add the multi_ref variable, but that's too late
> now.

Thanks. Yes, that cat is out of the bag and has been for a while unfortunately.

  Paul

> 
> Thanks, Roger.



Re: [PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-02-02 Thread Roger Pau Monné
On Thu, Jan 28, 2021 at 01:04:41PM +, Paul Durrant wrote:
> From: Paul Durrant 
> 
> Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid
> inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
> behaviour of xen-blkback when connecting to a frontend was:
> 
> - read 'ring-page-order'
> - if not present then expect a single page ring specified by 'ring-ref'
> - else expect a ring specified by 'ring-refX' where X is between 0 and
>   1 << ring-page-order
> 
> This was correct behaviour, but was broken by the afforementioned commit to
> become:
> 
> - read 'ring-page-order'
> - if not present then expect a single page ring (i.e. ring-page-order = 0)
> - expect a ring specified by 'ring-refX' where X is between 0 and
>   1 << ring-page-order
> - if that didn't work then see if there's a single page ring specified by
>   'ring-ref'
> 
> This incorrect behaviour works most of the time but fails when a frontend
> that sets 'ring-page-order' is unloaded and replaced by one that does not
> because, instead of reading 'ring-ref', xen-blkback will read the stale
> 'ring-ref0' left around by the previous frontend will try to map the wrong
> grant reference.
> 
> This patch restores the original behaviour.
> 
> Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid 
> inconsistent xenstore 'ring-page-order' set by malicious blkfront")
> Signed-off-by: Paul Durrant 
> ---
> Cc: Konrad Rzeszutek Wilk 
> Cc: "Roger Pau Monné" 
> Cc: Jens Axboe 
> Cc: Dongli Zhang 
> 
> v2:
>  - Remove now-spurious error path special-case when nr_grefs == 1
> ---
>  drivers/block/xen-blkback/common.h |  1 +
>  drivers/block/xen-blkback/xenbus.c | 38 +-
>  2 files changed, 17 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/block/xen-blkback/common.h 
> b/drivers/block/xen-blkback/common.h
> index b0c71d3a81a0..524a79f10de6 100644
> --- a/drivers/block/xen-blkback/common.h
> +++ b/drivers/block/xen-blkback/common.h
> @@ -313,6 +313,7 @@ struct xen_blkif {
>  
>   struct work_struct  free_work;
>   unsigned intnr_ring_pages;
> + boolmulti_ref;

You seem to have used spaces between the type and the variable name
here, while neighbors also use hard tabs.

The rest LGTM:

Reviewed-by: Roger Pau Monné 

We should have forbidden the usage of ring-page-order = 0 and we could
have avoided having to add the multi_ref variable, but that's too late
now.

Thanks, Roger.


RE: [PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-02-02 Thread Paul Durrant
> -Original Message-
> From: Xen-devel  On Behalf Of Dongli 
> Zhang
> Sent: 30 January 2021 05:09
> To: p...@xen.org; 'Jürgen Groß' ; 
> xen-de...@lists.xenproject.org; linux-
> bl...@vger.kernel.org; linux-kernel@vger.kernel.org
> Cc: 'Paul Durrant' ; 'Konrad Rzeszutek Wilk' 
> ; 'Roger Pau
> Monné' ; 'Jens Axboe' 
> Subject: Re: [PATCH v2] xen-blkback: fix compatibility bug with single page 
> rings
> 
> 
> 
> On 1/29/21 12:13 AM, Paul Durrant wrote:
> >> -Original Message-
> >> From: Jürgen Groß 
> >> Sent: 29 January 2021 07:35
> >> To: Dongli Zhang ; Paul Durrant ; 
> >> xen-
> >> de...@lists.xenproject.org; linux-bl...@vger.kernel.org; 
> >> linux-kernel@vger.kernel.org
> >> Cc: Paul Durrant ; Konrad Rzeszutek Wilk 
> >> ; Roger Pau
> >> Monné ; Jens Axboe 
> >> Subject: Re: [PATCH v2] xen-blkback: fix compatibility bug with single 
> >> page rings
> >>
> >> On 29.01.21 07:20, Dongli Zhang wrote:
> >>>
> >>>
> >>> On 1/28/21 5:04 AM, Paul Durrant wrote:
> >>>> From: Paul Durrant 
> >>>>
> >>>> Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to 
> >>>> avoid
> >>>> inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
> >>>> behaviour of xen-blkback when connecting to a frontend was:
> >>>>
> >>>> - read 'ring-page-order'
> >>>> - if not present then expect a single page ring specified by 'ring-ref'
> >>>> - else expect a ring specified by 'ring-refX' where X is between 0 and
> >>>>1 << ring-page-order
> >>>>
> >>>> This was correct behaviour, but was broken by the afforementioned commit 
> >>>> to
> >>>> become:
> >>>>
> >>>> - read 'ring-page-order'
> >>>> - if not present then expect a single page ring (i.e. ring-page-order = 
> >>>> 0)
> >>>> - expect a ring specified by 'ring-refX' where X is between 0 and
> >>>>1 << ring-page-order
> >>>> - if that didn't work then see if there's a single page ring specified by
> >>>>'ring-ref'
> >>>>
> >>>> This incorrect behaviour works most of the time but fails when a frontend
> >>>> that sets 'ring-page-order' is unloaded and replaced by one that does not
> >>>> because, instead of reading 'ring-ref', xen-blkback will read the stale
> >>>> 'ring-ref0' left around by the previous frontend will try to map the 
> >>>> wrong
> >>>> grant reference.
> >>>>
> >>>> This patch restores the original behaviour.
> >>>>
> >>>> Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid 
> >>>> inconsistent xenstore 'ring-
> page-
> >> order' set by malicious blkfront")
> >>>> Signed-off-by: Paul Durrant 
> >>>> ---
> >>>> Cc: Konrad Rzeszutek Wilk 
> >>>> Cc: "Roger Pau Monné" 
> >>>> Cc: Jens Axboe 
> >>>> Cc: Dongli Zhang 
> >>>>
> >>>> v2:
> >>>>   - Remove now-spurious error path special-case when nr_grefs == 1
> >>>> ---
> >>>>   drivers/block/xen-blkback/common.h |  1 +
> >>>>   drivers/block/xen-blkback/xenbus.c | 38 +-
> >>>>   2 files changed, 17 insertions(+), 22 deletions(-)
> >>>>
> >>>> diff --git a/drivers/block/xen-blkback/common.h 
> >>>> b/drivers/block/xen-blkback/common.h
> >>>> index b0c71d3a81a0..524a79f10de6 100644
> >>>> --- a/drivers/block/xen-blkback/common.h
> >>>> +++ b/drivers/block/xen-blkback/common.h
> >>>> @@ -313,6 +313,7 @@ struct xen_blkif {
> >>>>
> >>>>  struct work_struct  free_work;
> >>>>  unsigned intnr_ring_pages;
> >>>> +boolmulti_ref;
> >>>
> >>> Is it really necessary to introduce 'multi_ref' here or we may just re-use
> >>> 'nr_ring_pages'?
> >>>
> >>> According to blkfront code, 'ring-page-order' is set only when it is not 
> >>> zero,
> >>> that is, only when (info->nr_ring_pages > 1).
> >>
> >
> > That's how it is *supposed* to be. Windows certainly behaves that way too.
> >
> >> Did you look into all other OS's (Windows, OpenBSD, FreebSD, NetBSD,
> >> Solaris, Netware, other proprietary systems) implementations to verify
> >> that claim?
> >>
> >> I don't think so. So better safe than sorry.
> >>
> >
> > Indeed. It was unfortunate that the commit to blkif.h documenting 
> > multi-page (829f2a9c6dfae) was not
> crystal clear and (possibly as a consequence) blkback was implemented to read 
> ring-ref0 rather than
> ring-ref if ring-page-order was present and 0. Hence the only safe thing to 
> do is to restore that
> behaviour.
> >
> 
> Thank you very much for the explanation!
> 
> Reviewed-by: Dongli Zhang 
> 

Thanks.

Roger, Konrad, can I get a maintainer ack or otherwise, please?

  Paul




Re: [PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-01-30 Thread Dongli Zhang



On 1/29/21 12:13 AM, Paul Durrant wrote:
>> -Original Message-
>> From: Jürgen Groß 
>> Sent: 29 January 2021 07:35
>> To: Dongli Zhang ; Paul Durrant ; xen-
>> de...@lists.xenproject.org; linux-bl...@vger.kernel.org; 
>> linux-kernel@vger.kernel.org
>> Cc: Paul Durrant ; Konrad Rzeszutek Wilk 
>> ; Roger Pau
>> Monné ; Jens Axboe 
>> Subject: Re: [PATCH v2] xen-blkback: fix compatibility bug with single page 
>> rings
>>
>> On 29.01.21 07:20, Dongli Zhang wrote:
>>>
>>>
>>> On 1/28/21 5:04 AM, Paul Durrant wrote:
>>>> From: Paul Durrant 
>>>>
>>>> Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid
>>>> inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
>>>> behaviour of xen-blkback when connecting to a frontend was:
>>>>
>>>> - read 'ring-page-order'
>>>> - if not present then expect a single page ring specified by 'ring-ref'
>>>> - else expect a ring specified by 'ring-refX' where X is between 0 and
>>>>1 << ring-page-order
>>>>
>>>> This was correct behaviour, but was broken by the afforementioned commit to
>>>> become:
>>>>
>>>> - read 'ring-page-order'
>>>> - if not present then expect a single page ring (i.e. ring-page-order = 0)
>>>> - expect a ring specified by 'ring-refX' where X is between 0 and
>>>>1 << ring-page-order
>>>> - if that didn't work then see if there's a single page ring specified by
>>>>'ring-ref'
>>>>
>>>> This incorrect behaviour works most of the time but fails when a frontend
>>>> that sets 'ring-page-order' is unloaded and replaced by one that does not
>>>> because, instead of reading 'ring-ref', xen-blkback will read the stale
>>>> 'ring-ref0' left around by the previous frontend will try to map the wrong
>>>> grant reference.
>>>>
>>>> This patch restores the original behaviour.
>>>>
>>>> Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid 
>>>> inconsistent xenstore 'ring-page-
>> order' set by malicious blkfront")
>>>> Signed-off-by: Paul Durrant 
>>>> ---
>>>> Cc: Konrad Rzeszutek Wilk 
>>>> Cc: "Roger Pau Monné" 
>>>> Cc: Jens Axboe 
>>>> Cc: Dongli Zhang 
>>>>
>>>> v2:
>>>>   - Remove now-spurious error path special-case when nr_grefs == 1
>>>> ---
>>>>   drivers/block/xen-blkback/common.h |  1 +
>>>>   drivers/block/xen-blkback/xenbus.c | 38 +-
>>>>   2 files changed, 17 insertions(+), 22 deletions(-)
>>>>
>>>> diff --git a/drivers/block/xen-blkback/common.h 
>>>> b/drivers/block/xen-blkback/common.h
>>>> index b0c71d3a81a0..524a79f10de6 100644
>>>> --- a/drivers/block/xen-blkback/common.h
>>>> +++ b/drivers/block/xen-blkback/common.h
>>>> @@ -313,6 +313,7 @@ struct xen_blkif {
>>>>
>>>>struct work_struct  free_work;
>>>>unsigned intnr_ring_pages;
>>>> +  boolmulti_ref;
>>>
>>> Is it really necessary to introduce 'multi_ref' here or we may just re-use
>>> 'nr_ring_pages'?
>>>
>>> According to blkfront code, 'ring-page-order' is set only when it is not 
>>> zero,
>>> that is, only when (info->nr_ring_pages > 1).
>>
> 
> That's how it is *supposed* to be. Windows certainly behaves that way too.
> 
>> Did you look into all other OS's (Windows, OpenBSD, FreebSD, NetBSD,
>> Solaris, Netware, other proprietary systems) implementations to verify
>> that claim?
>>
>> I don't think so. So better safe than sorry.
>>
> 
> Indeed. It was unfortunate that the commit to blkif.h documenting multi-page 
> (829f2a9c6dfae) was not crystal clear and (possibly as a consequence) blkback 
> was implemented to read ring-ref0 rather than ring-ref if ring-page-order was 
> present and 0. Hence the only safe thing to do is to restore that behaviour.
> 

Thank you very much for the explanation!

Reviewed-by: Dongli Zhang 

Dongli ZHang


Re: [PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-01-28 Thread Jürgen Groß

On 29.01.21 07:20, Dongli Zhang wrote:



On 1/28/21 5:04 AM, Paul Durrant wrote:

From: Paul Durrant 

Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid
inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
behaviour of xen-blkback when connecting to a frontend was:

- read 'ring-page-order'
- if not present then expect a single page ring specified by 'ring-ref'
- else expect a ring specified by 'ring-refX' where X is between 0 and
   1 << ring-page-order

This was correct behaviour, but was broken by the afforementioned commit to
become:

- read 'ring-page-order'
- if not present then expect a single page ring (i.e. ring-page-order = 0)
- expect a ring specified by 'ring-refX' where X is between 0 and
   1 << ring-page-order
- if that didn't work then see if there's a single page ring specified by
   'ring-ref'

This incorrect behaviour works most of the time but fails when a frontend
that sets 'ring-page-order' is unloaded and replaced by one that does not
because, instead of reading 'ring-ref', xen-blkback will read the stale
'ring-ref0' left around by the previous frontend will try to map the wrong
grant reference.

This patch restores the original behaviour.

Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid inconsistent 
xenstore 'ring-page-order' set by malicious blkfront")
Signed-off-by: Paul Durrant 
---
Cc: Konrad Rzeszutek Wilk 
Cc: "Roger Pau Monné" 
Cc: Jens Axboe 
Cc: Dongli Zhang 

v2:
  - Remove now-spurious error path special-case when nr_grefs == 1
---
  drivers/block/xen-blkback/common.h |  1 +
  drivers/block/xen-blkback/xenbus.c | 38 +-
  2 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/drivers/block/xen-blkback/common.h 
b/drivers/block/xen-blkback/common.h
index b0c71d3a81a0..524a79f10de6 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -313,6 +313,7 @@ struct xen_blkif {
  
  	struct work_struct	free_work;

unsigned intnr_ring_pages;
+   boolmulti_ref;


Is it really necessary to introduce 'multi_ref' here or we may just re-use
'nr_ring_pages'?

According to blkfront code, 'ring-page-order' is set only when it is not zero,
that is, only when (info->nr_ring_pages > 1).


Did you look into all other OS's (Windows, OpenBSD, FreebSD, NetBSD,
Solaris, Netware, other proprietary systems) implementations to verify
that claim?

I don't think so. So better safe than sorry.


Juergen


OpenPGP_0xB0DE9DD628BF132F.asc
Description: application/pgp-keys


OpenPGP_signature
Description: OpenPGP digital signature


Re: [PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-01-28 Thread Dongli Zhang



On 1/28/21 5:04 AM, Paul Durrant wrote:
> From: Paul Durrant 
> 
> Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid
> inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
> behaviour of xen-blkback when connecting to a frontend was:
> 
> - read 'ring-page-order'
> - if not present then expect a single page ring specified by 'ring-ref'
> - else expect a ring specified by 'ring-refX' where X is between 0 and
>   1 << ring-page-order
> 
> This was correct behaviour, but was broken by the afforementioned commit to
> become:
> 
> - read 'ring-page-order'
> - if not present then expect a single page ring (i.e. ring-page-order = 0)
> - expect a ring specified by 'ring-refX' where X is between 0 and
>   1 << ring-page-order
> - if that didn't work then see if there's a single page ring specified by
>   'ring-ref'
> 
> This incorrect behaviour works most of the time but fails when a frontend
> that sets 'ring-page-order' is unloaded and replaced by one that does not
> because, instead of reading 'ring-ref', xen-blkback will read the stale
> 'ring-ref0' left around by the previous frontend will try to map the wrong
> grant reference.
> 
> This patch restores the original behaviour.
> 
> Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid 
> inconsistent xenstore 'ring-page-order' set by malicious blkfront")
> Signed-off-by: Paul Durrant 
> ---
> Cc: Konrad Rzeszutek Wilk 
> Cc: "Roger Pau Monné" 
> Cc: Jens Axboe 
> Cc: Dongli Zhang 
> 
> v2:
>  - Remove now-spurious error path special-case when nr_grefs == 1
> ---
>  drivers/block/xen-blkback/common.h |  1 +
>  drivers/block/xen-blkback/xenbus.c | 38 +-
>  2 files changed, 17 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/block/xen-blkback/common.h 
> b/drivers/block/xen-blkback/common.h
> index b0c71d3a81a0..524a79f10de6 100644
> --- a/drivers/block/xen-blkback/common.h
> +++ b/drivers/block/xen-blkback/common.h
> @@ -313,6 +313,7 @@ struct xen_blkif {
>  
>   struct work_struct  free_work;
>   unsigned intnr_ring_pages;
> + boolmulti_ref;

Is it really necessary to introduce 'multi_ref' here or we may just re-use
'nr_ring_pages'?

According to blkfront code, 'ring-page-order' is set only when it is not zero,
that is, only when (info->nr_ring_pages > 1).

1819 if (info->nr_ring_pages > 1) {
1820 err = xenbus_printf(xbt, dev->nodename, "ring-page-order",
"%u",
1821 ring_page_order);
1822 if (err) {
1823 message = "writing ring-page-order";
1824 goto abort_transaction;
1825 }
1826 }

Therefore, can we assume 'ring-page-order' can never be 0? Once we have
'ring-page-order' set, it should be >= 1 and we should read from "ring-ref%u"?

If the specification allows 'ring-page-order' to be zero with "ring-ref%u"
available, we should introduce 'multi_ref'.

Thank you very much!

Dongli Zhang


>   /* All rings for this device. */
>   struct xen_blkif_ring   *rings;
>   unsigned intnr_rings;
> diff --git a/drivers/block/xen-blkback/xenbus.c 
> b/drivers/block/xen-blkback/xenbus.c
> index 9860d4842f36..6c5e9373e91c 100644
> --- a/drivers/block/xen-blkback/xenbus.c
> +++ b/drivers/block/xen-blkback/xenbus.c
> @@ -998,14 +998,17 @@ static int read_per_ring_refs(struct xen_blkif_ring 
> *ring, const char *dir)
>   for (i = 0; i < nr_grefs; i++) {
>   char ring_ref_name[RINGREF_NAME_LEN];
>  
> - snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i);
> + if (blkif->multi_ref)
> + snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", 
> i);
> + else {
> + WARN_ON(i != 0);
> + snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref");
> + }
> +
>   err = xenbus_scanf(XBT_NIL, dir, ring_ref_name,
>  "%u", _ref[i]);
>  
>   if (err != 1) {
> - if (nr_grefs == 1)
> - break;
> -
>   err = -EINVAL;
>   xenbus_dev_fatal(dev, err, "reading %s/%s",
>dir, ring_ref_name);
> @@ -1013,18 +1016,6 @@ static int read_per_ring_refs(struct xen_blkif_ring 
> *ring, const char *dir)
>   }
>   }
>  
> - if (err != 1) {
> - WARN_ON(nr_grefs != 1);
> -
> - err = xenbus_scanf(XBT_NIL, dir, "ring-ref", "%u",
> -_ref[0]);
> - if (err != 1) {
> - err = -EINVAL;
> - xenbus_dev_fatal(dev, err, "reading %s/ring-ref", dir);
> - return err;
> - }
> - }
> -
>   err = -ENOMEM;
>   for (i = 0; i < nr_grefs * 

[PATCH v2] xen-blkback: fix compatibility bug with single page rings

2021-01-28 Thread Paul Durrant
From: Paul Durrant 

Prior to commit 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid
inconsistent xenstore 'ring-page-order' set by malicious blkfront"), the
behaviour of xen-blkback when connecting to a frontend was:

- read 'ring-page-order'
- if not present then expect a single page ring specified by 'ring-ref'
- else expect a ring specified by 'ring-refX' where X is between 0 and
  1 << ring-page-order

This was correct behaviour, but was broken by the afforementioned commit to
become:

- read 'ring-page-order'
- if not present then expect a single page ring (i.e. ring-page-order = 0)
- expect a ring specified by 'ring-refX' where X is between 0 and
  1 << ring-page-order
- if that didn't work then see if there's a single page ring specified by
  'ring-ref'

This incorrect behaviour works most of the time but fails when a frontend
that sets 'ring-page-order' is unloaded and replaced by one that does not
because, instead of reading 'ring-ref', xen-blkback will read the stale
'ring-ref0' left around by the previous frontend will try to map the wrong
grant reference.

This patch restores the original behaviour.

Fixes: 4a8c31a1c6f5 ("xen/blkback: rework connect_ring() to avoid inconsistent 
xenstore 'ring-page-order' set by malicious blkfront")
Signed-off-by: Paul Durrant 
---
Cc: Konrad Rzeszutek Wilk 
Cc: "Roger Pau Monné" 
Cc: Jens Axboe 
Cc: Dongli Zhang 

v2:
 - Remove now-spurious error path special-case when nr_grefs == 1
---
 drivers/block/xen-blkback/common.h |  1 +
 drivers/block/xen-blkback/xenbus.c | 38 +-
 2 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/drivers/block/xen-blkback/common.h 
b/drivers/block/xen-blkback/common.h
index b0c71d3a81a0..524a79f10de6 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -313,6 +313,7 @@ struct xen_blkif {
 
struct work_struct  free_work;
unsigned intnr_ring_pages;
+   boolmulti_ref;
/* All rings for this device. */
struct xen_blkif_ring   *rings;
unsigned intnr_rings;
diff --git a/drivers/block/xen-blkback/xenbus.c 
b/drivers/block/xen-blkback/xenbus.c
index 9860d4842f36..6c5e9373e91c 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -998,14 +998,17 @@ static int read_per_ring_refs(struct xen_blkif_ring 
*ring, const char *dir)
for (i = 0; i < nr_grefs; i++) {
char ring_ref_name[RINGREF_NAME_LEN];
 
-   snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i);
+   if (blkif->multi_ref)
+   snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", 
i);
+   else {
+   WARN_ON(i != 0);
+   snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref");
+   }
+
err = xenbus_scanf(XBT_NIL, dir, ring_ref_name,
   "%u", _ref[i]);
 
if (err != 1) {
-   if (nr_grefs == 1)
-   break;
-
err = -EINVAL;
xenbus_dev_fatal(dev, err, "reading %s/%s",
 dir, ring_ref_name);
@@ -1013,18 +1016,6 @@ static int read_per_ring_refs(struct xen_blkif_ring 
*ring, const char *dir)
}
}
 
-   if (err != 1) {
-   WARN_ON(nr_grefs != 1);
-
-   err = xenbus_scanf(XBT_NIL, dir, "ring-ref", "%u",
-  _ref[0]);
-   if (err != 1) {
-   err = -EINVAL;
-   xenbus_dev_fatal(dev, err, "reading %s/ring-ref", dir);
-   return err;
-   }
-   }
-
err = -ENOMEM;
for (i = 0; i < nr_grefs * XEN_BLKIF_REQS_PER_PAGE; i++) {
req = kzalloc(sizeof(*req), GFP_KERNEL);
@@ -1129,10 +1120,15 @@ static int connect_ring(struct backend_info *be)
 blkif->nr_rings, blkif->blk_protocol, protocol,
 blkif->vbd.feature_gnt_persistent ? "persistent grants" : "");
 
-   ring_page_order = xenbus_read_unsigned(dev->otherend,
-  "ring-page-order", 0);
-
-   if (ring_page_order > xen_blkif_max_ring_order) {
+   err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-page-order", "%u",
+  _page_order);
+   if (err != 1) {
+   blkif->nr_ring_pages = 1;
+   blkif->multi_ref = false;
+   } else if (ring_page_order <= xen_blkif_max_ring_order) {
+   blkif->nr_ring_pages = 1 << ring_page_order;
+   blkif->multi_ref = true;
+   } else {
err = -EINVAL;
xenbus_dev_fatal(dev, err,
 "requested ring page order %d exceed max:%d",
@@ -1141,8 +1137,6 @@ static int