[PATCH v3] arm/ioreq: guard interaction data on read/write operations

2023-10-05 Thread Andrii Chepurnyi
For read operations, there's a potential issue when the data field
of the ioreq struct is partially updated in the response. To address
this, zero data field during read operations. This modification
serves as a safeguard against implementations that may inadvertently
partially update the data field in response to read requests.
For instance, consider an 8-bit read operation. In such cases, QEMU,
returns the same content of the data field with only 8 bits of
updated data. This behavior could potentially result in the
propagation of incorrect or unintended data to ioreq clients.
During a write access, the Device Model only need to know the content
of the bits associated with the access size (e.g. for 8-bit, the lower
8-bits). During a read access, the Device Model don't need to know any
value. So restrict the value it can access.

Signed-off-by: Andrii Chepurnyi 
Release-acked-by: Henry Wang 
---
 xen/arch/arm/ioreq.c | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/ioreq.c b/xen/arch/arm/ioreq.c
index 3bed0a14c0..5df755b48b 100644
--- a/xen/arch/arm/ioreq.c
+++ b/xen/arch/arm/ioreq.c
@@ -17,6 +17,8 @@ enum io_state handle_ioserv(struct cpu_user_regs *regs, 
struct vcpu *v)
 {
 const union hsr hsr = { .bits = regs->hsr };
 const struct hsr_dabt dabt = hsr.dabt;
+const uint8_t access_size = (1U << dabt.size) * 8;
+const uint64_t access_mask = GENMASK_ULL(access_size - 1, 0);
 /* Code is similar to handle_read */
 register_t r = v->io.req.data;
 
@@ -26,6 +28,12 @@ enum io_state handle_ioserv(struct cpu_user_regs *regs, 
struct vcpu *v)
 if ( dabt.write )
 return IO_HANDLED;
 
+/*
+ * The Arm Arm requires the value to be zero-extended to the size
+ * of the register. The Device Model is not meant to touch the bits
+ * outside of the access size, but let's not trust that.
+ */
+r &= access_mask;
 r = sign_extend(dabt, r);
 
 set_user_reg(regs, dabt.reg, r);
@@ -39,6 +47,8 @@ enum io_state try_fwd_ioserv(struct cpu_user_regs *regs,
 struct vcpu_io *vio = >io;
 const struct instr_details instr = info->dabt_instr;
 struct hsr_dabt dabt = info->dabt;
+const uint8_t access_size = (1U << dabt.size) * 8;
+const uint64_t access_mask = GENMASK_ULL(access_size - 1, 0);
 ioreq_t p = {
 .type = IOREQ_TYPE_COPY,
 .addr = info->gpa,
@@ -80,7 +90,13 @@ enum io_state try_fwd_ioserv(struct cpu_user_regs *regs,
 
 ASSERT(dabt.valid);
 
-p.data = get_user_reg(regs, info->dabt.reg);
+/*
+ * During a write access, the Device Model only need to know the content
+ * of the bits associated with the access size (e.g. for 8-bit, the lower 
8-bits).
+ * During a read access, the Device Model don't need to know any value.
+ * So restrict the value it can access.
+ */
+p.data = p.dir ? 0 : get_user_reg(regs, info->dabt.reg) & access_mask;
 vio->req = p;
 vio->suspended = false;
 vio->info.dabt_instr = instr;
-- 
2.25.1



[PATCH v2] arm/ioreq: guard interaction data on read/write operations

2023-10-05 Thread Andrii Chepurnyi
For read operations, there's a potential issue when the data field
of the ioreq struct is partially updated in the response. To address
this, zero data field during read operations. This modification
serves as a safeguard against implementations that may inadvertently
partially update the data field in response to read requests.
For instance, consider an 8-bit read operation. In such cases, QEMU,
returns the same content of the dat field with only 8 bits of
updated data. This behavior could potentially result in the
propagation of incorrect or unintended data to ioreq clients.
There is also a good point to guard interaction data with actual size
of the interaction.

Signed-off-by: Andrii Chepurnyi 
---
 xen/arch/arm/ioreq.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/ioreq.c b/xen/arch/arm/ioreq.c
index 3bed0a14c0..26dae8ca28 100644
--- a/xen/arch/arm/ioreq.c
+++ b/xen/arch/arm/ioreq.c
@@ -17,6 +17,8 @@ enum io_state handle_ioserv(struct cpu_user_regs *regs, 
struct vcpu *v)
 {
 const union hsr hsr = { .bits = regs->hsr };
 const struct hsr_dabt dabt = hsr.dabt;
+const uint8_t access_size = (1 << dabt.size) * 8;
+const uint64_t access_mask = GENMASK_ULL(access_size - 1, 0);
 /* Code is similar to handle_read */
 register_t r = v->io.req.data;
 
@@ -26,6 +28,7 @@ enum io_state handle_ioserv(struct cpu_user_regs *regs, 
struct vcpu *v)
 if ( dabt.write )
 return IO_HANDLED;
 
+r &= access_mask;
 r = sign_extend(dabt, r);
 
 set_user_reg(regs, dabt.reg, r);
@@ -39,6 +42,8 @@ enum io_state try_fwd_ioserv(struct cpu_user_regs *regs,
 struct vcpu_io *vio = >io;
 const struct instr_details instr = info->dabt_instr;
 struct hsr_dabt dabt = info->dabt;
+const uint8_t access_size = (1 << dabt.size) * 8;
+const uint64_t access_mask = GENMASK_ULL(access_size - 1, 0);
 ioreq_t p = {
 .type = IOREQ_TYPE_COPY,
 .addr = info->gpa,
@@ -79,8 +84,7 @@ enum io_state try_fwd_ioserv(struct cpu_user_regs *regs,
 return IO_HANDLED;
 
 ASSERT(dabt.valid);
-
-p.data = get_user_reg(regs, info->dabt.reg);
+p.data = p.dir ? 0 : get_user_reg(regs, info->dabt.reg) & access_mask;
 vio->req = p;
 vio->suspended = false;
 vio->info.dabt_instr = instr;
-- 
2.25.1



Re: [PATCH] arm/ioreq: clean data field in ioreq struct on read operations

2023-10-05 Thread Andrii Chepurnyi
Hello,

On 10/4/23 18:41, Julien Grall wrote:

> I was asking a pointer to the code in the Device Emulator (QEMU in your 
> case). I am confident the code is correct in U-boot, because when using 
> 'w0', the unused bits are meant to be set to zero (per the Arm Arm). But 
> I am curious to know why QEMU is not doing it.

QEMU flow in the case of the read operation should be the following:

https://github.com/xen-troops/qemu/blob/v7.0.0-xt/hw/xen/xen-hvm-common.c#L389
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/hw/xen/xen-hvm-common.c#L408
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/hw/xen/xen-hvm-common.c#L309
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/hw/xen/xen-hvm-common.c#L228
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/softmmu/physmem.c#L3002
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/softmmu/physmem.c#L2973
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/softmmu/physmem.c#L2942
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/softmmu/physmem.c#L2926
https://github.com/xen-troops/qemu/blob/v7.0.0-xt/softmmu/physmem.c#L2876

 From my understanding, only the quantity of requested bytes is updated.

Best regards,


Re: [PATCH] arm/ioreq: clean data field in ioreq struct on read operations

2023-10-04 Thread Andrii Chepurnyi
Hello,

On 10/3/23 16:49, Julien Grall wrote:
> Hi,
> 
> On 03/10/2023 14:19, Andrii Chepurnyi wrote:
>> For read operations, there's a potential issue when the data field
>> of the ioreq struct is partially updated in the response. To address
>> this, zero data field during read operations. This modification
>> serves as a safeguard against implementations that may inadvertently
>> partially update the data field in response to read requests.
>> For instance, consider an 8-bit read operation. In such cases, QEMU,
>> returns the same content of the data field with only 8 bits of
>> updated data. 
> 
> Do you have a pointer to the code?

First of all, using the term "user-space" with respect to this problem 
was a mistake from my side.

In general, my use case is to run u-boot with virtio-blk inside the 
guest domain.
I.e. setup configuration(hardware renesas gen3 kingfisher board):  Dom0, 
DomD ( QEMU as backend) and running u-boot in DomA with virtio-blk.
The problem appeared inside the u-boot code :

static int virtio_pci_reset(struct udevice *udev)
{
struct virtio_pci_priv *priv = dev_get_priv(udev);

/* 0 status means a reset */
iowrite8(0, >common->device_status);

/*
 * After writing 0 to device_status, the driver MUST wait for a read
 * of device_status to return 0 before reinitializing the device.
 * This will flush out the status write, and flush in device writes,
 * including MSI-X interrupts, if any.
 */
while (ioread8(>common->device_status))
udelay(1000);

return 0;
}


I found that if u-boot was built with clang, it stuck in while in 
virtio_pci_reset forever. At the same time with gcc is working.

Here is a part disassembly of the virtio_pci_reset for both cases:

gcc:

 :
0:   a9be7bfdstp x29, x30, [sp, #-32]!
4:   910003fdmov x29, sp
8:   f9000bf3str x19, [sp, #16]
c:   9400bl  0 
   10:   aa0003f3mov x19, x0
   14:   f940ldr x0, [x0]
   18:   d5033fbfdmb sy
   1c:   3900501fstrbwzr, [x0, #20]
   20:   f9400260ldr x0, [x19]
   24:   39405000ldrbw0, [x0, #20]
   28:   12001c00and w0, w0, #0xff
   2c:   d5033fbfdmb sy
   30:   3580cbnzw0, 40 
   34:   f9400bf3ldr x19, [sp, #16]
   38:   a8c27bfdldp x29, x30, [sp], #32
   3c:   d65f03c0ret
   40:   d2807d00mov x0, #0x3e8  // #1000
   44:   9400bl  0 
   48:   17f6b   20 


clang:

 :
0:   a9be7bfdstp x29, x30, [sp, #-32]!
4:   f9000bf3str x19, [sp, #16]
8:   910003fdmov x29, sp
c:   9400bl  0 
   10:   f948ldr x8, [x0]
   14:   d5033fbfdmb sy
   18:   3900511fstrbwzr, [x8, #20]
   1c:   f948ldr x8, [x0]
   20:   39405108ldrbw8, [x8, #20]
   24:   d5033fbfdmb sy
   28:   34000108cbz w8, 48 
   2c:   aa0003f3mov x19, x0
   30:   52807d00mov w0, #0x3e8  // #1000
   34:   9400bl  0 
   38:   f9400268ldr x8, [x19]
   3c:   39405108ldrbw8, [x8, #20]
   40:   d5033fbfdmb sy
   44:   3568cbnzw8, 30 
   48:   f9400bf3ldr x19, [sp, #16]
   4c:   2a1f03e0mov w0, wzr
   50:   a8c27bfdldp x29, x30, [sp], #32
   54:   d65f03c0ret


As you may found, in case of gcc read of 8 bit data :

   24:   39405000ldrbw0, [x0, #20]
   28:   12001c00and w0, w0, #0xff
   2c:   d5033fbfdmb sy

in case of clang:

   20:   39405108ldrbw8, [x8, #20]
   24:   d5033fbfdmb sy

in second case we got trash inside upper bits w8 and loop forever.


> 
>> This behavior could potentially result in the
>> propagation of incorrect or unintended data to user-space applications.
> 
> I am a bit confused with the last sentence. Are you referring to the 
> device emulator or a guest user-space applications? If the latter, then 
> why are you singling out user-space applications?

I will rephrase description, since u-boot is not a "user-space 
applications".

> To take the 8-bits example, the assumption is that QEMU will not touch 
> the top 24-bits. I guess that's a fair assumption. But, at this point, I 
> feel it would be better to also zero the top 24-bits in handle_ioserv() 
> when writing back to the register.
> 
> Also, if you are worried about unintended data shared, then we should 
> also make the value of get_user_reg() to only share what matters to the 
> device model.

Ok, I will push v2 with respect to your comments.

Best regards,
Andrii.


[PATCH] arm/ioreq: clean data field in ioreq struct on read operations

2023-10-04 Thread Andrii Chepurnyi
For read operations, there's a potential issue when the data field
of the ioreq struct is partially updated in the response. To address
this, zero data field during read operations. This modification
serves as a safeguard against implementations that may inadvertently
partially update the data field in response to read requests.
For instance, consider an 8-bit read operation. In such cases, QEMU,
returns the same content of the data field with only 8 bits of
updated data. This behavior could potentially result in the
propagation of incorrect or unintended data to user-space applications.

Signed-off-by: Andrii Chepurnyi 
---
 xen/arch/arm/ioreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/arm/ioreq.c b/xen/arch/arm/ioreq.c
index 3bed0a14c0..aaa2842acc 100644
--- a/xen/arch/arm/ioreq.c
+++ b/xen/arch/arm/ioreq.c
@@ -80,7 +80,7 @@ enum io_state try_fwd_ioserv(struct cpu_user_regs *regs,
 
 ASSERT(dabt.valid);
 
-p.data = get_user_reg(regs, info->dabt.reg);
+p.data = (p.dir) ? 0 : get_user_reg(regs, info->dabt.reg);
 vio->req = p;
 vio->suspended = false;
 vio->info.dabt_instr = instr;
-- 
2.25.1



Re: [PATCH v4 0/3] xen-blk{back,front}: Fix two bugs in 'feature_persistent'

2022-07-18 Thread Andrii Chepurnyi
Hello SeongJae,

Thanks for the efforts.
I've tested backend patches(1,2) on my custom 5.10 kernel (since I
can't test on vanilla) and it works for me.

Best regards,
Andrii


On Sat, Jul 16, 2022 at 1:51 AM SeongJae Park  wrote:
>
> Introduction of 'feature_persistent' made two bugs.  First one is wrong
> overwrite of 'vbd->feature_gnt_persistent' in 'blkback' due to wrong
> parameter value caching position, and the second one is unintended
> behavioral change that could break previous dynamic frontend/backend
> persistent feature support changes.  This patchset fixes the issues.
>
> Changes from v3
> (https://lore.kernel.org/xen-devel/20220715175521.126649-1...@kernel.org/)
> - Split 'blkback' patch for each of the two issues
> - Add 'Reported-by: Andrii Chepurnyi '
>
> Changes from v2
> (https://lore.kernel.org/xen-devel/20220714224410.51147-1...@kernel.org/)
> - Keep the behavioral change of v1
> - Update blkfront's counterpart to follow the changed behavior
> - Update documents for the changed behavior
>
> Changes from v1
> (https://lore.kernel.org/xen-devel/20220106091013.126076-1-mhe...@amazon.de/)
> - Avoid the behavioral change
>   (https://lore.kernel.org/xen-devel/20220121102309.27802-1...@kernel.org/)
> - Rebase on latest xen/tip/linux-next
> - Re-work by SeongJae Park 
> - Cc stable@
>
> Maximilian Heyne (1):
>   xen-blkback: Apply 'feature_persistent' parameter when connect
>
> SeongJae Park (2):
>   xen-blkback: fix persistent grants negotiation
>   xen-blkfront: Apply 'feature_persistent' parameter when connect
>
>  .../ABI/testing/sysfs-driver-xen-blkback  |  2 +-
>  .../ABI/testing/sysfs-driver-xen-blkfront |  2 +-
>  drivers/block/xen-blkback/xenbus.c| 20 ---
>  drivers/block/xen-blkfront.c  |  4 +---
>  4 files changed, 11 insertions(+), 17 deletions(-)
>
> --
> 2.25.1
>



Re: [PATCH v2] xen-blkback: fix persistent grants negotiation

2022-07-15 Thread Andrii Chepurnyi
Hello All,

I faced the mentioned issue recently and just to bring more context here is
our setup:
We use pvblock backend for Android guest. It starts using u-boot with
pvblock support(which frontend doesn't support the persistent grants
feature), later it loads and starts the Linux kernel(which frontend
supports the persistent grants feature). So in total, we have sequent two
different frontends reconnection, the first of which doesn't support
persistent grants.
So the original patch [1] perfectly solves the original issue and provides
the ability to use persistent grants after the reconnection when Linux
frontend which supports persistent grants comes into play.
At the same time [2] will disable the persistent grants feature for the
first and second frontend.
Is it possible to keep [1]  as is?

[1]
https://lore.kernel.org/xen-devel/20220106091013.126076-1-mhe...@amazon.de/
[2] https://lore.kernel.org/xen-devel/20220714224410.51147-1...@kernel.org/

Best regards,
Andrii

On Fri, Jul 15, 2022 at 1:15 PM Oleksandr  wrote:

>
> On 15.07.22 01:44, SeongJae Park wrote:
>
>
> Hello all.
>
> Adding Andrii Chepurnyi to CC who have played with the use-case which
> required reconnect recently and faced some issues with
> feature_persistent handling.
>
>
>
>
> > Persistent grants feature can be used only when both backend and the
> > frontend supports the feature.  The feature was always supported by
> > 'blkback', but commit aac8a70db24b ("xen-blkback: add a parameter for
> > disabling of persistent grants") has introduced a parameter for
> > disabling it runtime.
> >
> > To avoid the parameter be updated while being used by 'blkback', the
> > commit caches the parameter into 'vbd->feature_gnt_persistent' in
> > 'xen_vbd_create()', and then check if the guest also supports the
> > feature and finally updates the field in 'connect_ring()'.
> >
> > However, 'connect_ring()' could be called before 'xen_vbd_create()', so
> > later execution of 'xen_vbd_create()' can wrongly overwrite 'true' to
> > 'vbd->feature_gnt_persistent'.  As a result, 'blkback' could try to use
> > 'persistent grants' feature even if the guest doesn't support the
> > feature.
> >
> > This commit fixes the issue by moving the parameter value caching to
> > 'xen_blkif_alloc()', which allocates the 'blkif'.  Because the struct
> > embeds 'vbd' object, which will be used by 'connect_ring()' later, this
> > should be called before 'connect_ring()' and therefore this should be
> > the right and safe place to do the caching.
> >
> > Fixes: aac8a70db24b ("xen-blkback: add a parameter for disabling of
> persistent grants")
> > Cc:  # 5.10.x
> > Signed-off-by: Maximilian Heyne 
> > Signed-off-by: SeongJae Park 
> > ---
> >
> > Changes from v1[1]
> > - Avoid the behavioral change[2]
> > - Rebase on latest xen/tip/linux-next
> > - Re-work by SeongJae Park 
> > - Cc stable@
> >
> > [1]
> https://lore.kernel.org/xen-devel/20220106091013.126076-1-mhe...@amazon.de/
> > [2]
> https://lore.kernel.org/xen-devel/20220121102309.27802-1...@kernel.org/
> >
> >   drivers/block/xen-blkback/xenbus.c | 15 +++
> >   1 file changed, 7 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/block/xen-blkback/xenbus.c
> b/drivers/block/xen-blkback/xenbus.c
> > index 97de13b14175..16c6785d260c 100644
> > --- a/drivers/block/xen-blkback/xenbus.c
> > +++ b/drivers/block/xen-blkback/xenbus.c
> > @@ -157,6 +157,11 @@ static int xen_blkif_alloc_rings(struct xen_blkif
> *blkif)
> >   return 0;
> >   }
> >
> > +/* Enable the persistent grants feature. */
> > +static bool feature_persistent = true;
> > +module_param(feature_persistent, bool, 0644);
> > +MODULE_PARM_DESC(feature_persistent, "Enables the persistent grants
> feature");
> > +
> >   static struct xen_blkif *xen_blkif_alloc(domid_t domid)
> >   {
> >   struct xen_blkif *blkif;
> > @@ -181,6 +186,8 @@ static struct xen_blkif *xen_blkif_alloc(domid_t
> domid)
> >   __module_get(THIS_MODULE);
> >   INIT_WORK(>free_work, xen_blkif_deferred_free);
> >
> > + blkif->vbd.feature_gnt_persistent = feature_persistent;
> > +
> >   return blkif;
> >   }
> >
> > @@ -472,12 +479,6 @@ static void xen_vbd_free(struct xen_vbd *vbd)
> >   vbd->bdev = NULL;
> >   }
> >
> > -/* Enable the persistent grants feature. */
> > -static bool feature_persistent = true;
> > -module_param(feature_persistent, bool, 0644);
> > -MODULE_PARM_DESC(feature_persistent,
>