Michael S. Tsirkin
2020-Apr-06 12:50 UTC
[PATCH] vhost: force spec specified alignment on types
The ring element addresses are passed between components with different alignments assumptions. Thus, if guest/userspace selects a pointer and host then gets and dereferences it, we might need to decrease the compiler-selected alignment to prevent compiler on the host from assuming pointer is aligned. This actually triggers on ARM with -mabi=apcs-gnu - which is a deprecated configuration, but it seems safer to handle this generally. I verified that the produced binary is exactly identical on x86. Signed-off-by: Michael S. Tsirkin <mst at redhat.com> --- This is my preferred way to handle the ARM incompatibility issues (in preference to kconfig hacks). I will push this into next now. Comments? drivers/vhost/vhost.h | 6 ++--- include/uapi/linux/virtio_ring.h | 41 ++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index cc82918158d2..a67bda9792ec 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -74,9 +74,9 @@ struct vhost_virtqueue { /* The actual ring of buffers. */ struct mutex mutex; unsigned int num; - struct vring_desc __user *desc; - struct vring_avail __user *avail; - struct vring_used __user *used; + vring_desc_t __user *desc; + vring_avail_t __user *avail; + vring_used_t __user *used; const struct vhost_iotlb_map *meta_iotlb[VHOST_NUM_ADDRS]; struct vhost_desc *descs; diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h index 559f42e73315..cd6e0b2eaf2f 100644 --- a/include/uapi/linux/virtio_ring.h +++ b/include/uapi/linux/virtio_ring.h @@ -118,16 +118,6 @@ struct vring_used { struct vring_used_elem ring[]; }; -struct vring { - unsigned int num; - - struct vring_desc *desc; - - struct vring_avail *avail; - - struct vring_used *used; -}; - /* Alignment requirements for vring elements. * When using pre-virtio 1.0 layout, these fall out naturally. */ @@ -164,6 +154,37 @@ struct vring { #define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) #define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num]) +/* + * The ring element addresses are passed between components with different + * alignments assumptions. Thus, we might need to decrease the compiler-selected + * alignment, and so must use a typedef to make sure the __aligned attribute + * actually takes hold: + * + * https://gcc.gnu.org/onlinedocs//gcc/Common-Type-Attributes.html#Common-Type-Attributes + * + * When used on a struct, or struct member, the aligned attribute can only + * increase the alignment; in order to decrease it, the packed attribute must + * be specified as well. When used as part of a typedef, the aligned attribute + * can both increase and decrease alignment, and specifying the packed + * attribute generates a warning. + */ +typedef struct vring_desc __attribute__((aligned(VRING_DESC_ALIGN_SIZE))) + vring_desc_t; +typedef struct vring_avail __attribute__((aligned(VRING_AVAIL_ALIGN_SIZE))) + vring_avail_t; +typedef struct vring_used __attribute__((aligned(VRING_USED_ALIGN_SIZE))) + vring_used_t; + +struct vring { + unsigned int num; + + vring_desc_t *desc; + + vring_avail_t *avail; + + vring_used_t *used; +}; + static inline void vring_init(struct vring *vr, unsigned int num, void *p, unsigned long align) { -- MST
On 2020/4/6 ??8:50, Michael S. Tsirkin wrote:> The ring element addresses are passed between components with different > alignments assumptions. Thus, if guest/userspace selects a pointer and > host then gets and dereferences it, we might need to decrease the > compiler-selected alignment to prevent compiler on the host from > assuming pointer is aligned. > > This actually triggers on ARM with -mabi=apcs-gnu - which is a > deprecated configuration, but it seems safer to handle this > generally. > > I verified that the produced binary is exactly identical on x86. > > Signed-off-by: Michael S. Tsirkin <mst at redhat.com> > --- > > This is my preferred way to handle the ARM incompatibility issues > (in preference to kconfig hacks). > I will push this into next now. > Comments?I'm not sure if it's too late to fix. It would still be still problematic for the userspace that is using old uapi headers? Thanks> > drivers/vhost/vhost.h | 6 ++--- > include/uapi/linux/virtio_ring.h | 41 ++++++++++++++++++++++++-------- > 2 files changed, 34 insertions(+), 13 deletions(-) > > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > index cc82918158d2..a67bda9792ec 100644 > --- a/drivers/vhost/vhost.h > +++ b/drivers/vhost/vhost.h > @@ -74,9 +74,9 @@ struct vhost_virtqueue { > /* The actual ring of buffers. */ > struct mutex mutex; > unsigned int num; > - struct vring_desc __user *desc; > - struct vring_avail __user *avail; > - struct vring_used __user *used; > + vring_desc_t __user *desc; > + vring_avail_t __user *avail; > + vring_used_t __user *used; > const struct vhost_iotlb_map *meta_iotlb[VHOST_NUM_ADDRS]; > > struct vhost_desc *descs; > diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h > index 559f42e73315..cd6e0b2eaf2f 100644 > --- a/include/uapi/linux/virtio_ring.h > +++ b/include/uapi/linux/virtio_ring.h > @@ -118,16 +118,6 @@ struct vring_used { > struct vring_used_elem ring[]; > }; > > -struct vring { > - unsigned int num; > - > - struct vring_desc *desc; > - > - struct vring_avail *avail; > - > - struct vring_used *used; > -}; > - > /* Alignment requirements for vring elements. > * When using pre-virtio 1.0 layout, these fall out naturally. > */ > @@ -164,6 +154,37 @@ struct vring { > #define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) > #define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num]) > > +/* > + * The ring element addresses are passed between components with different > + * alignments assumptions. Thus, we might need to decrease the compiler-selected > + * alignment, and so must use a typedef to make sure the __aligned attribute > + * actually takes hold: > + * > + * https://gcc.gnu.org/onlinedocs//gcc/Common-Type-Attributes.html#Common-Type-Attributes > + * > + * When used on a struct, or struct member, the aligned attribute can only > + * increase the alignment; in order to decrease it, the packed attribute must > + * be specified as well. When used as part of a typedef, the aligned attribute > + * can both increase and decrease alignment, and specifying the packed > + * attribute generates a warning. > + */ > +typedef struct vring_desc __attribute__((aligned(VRING_DESC_ALIGN_SIZE))) > + vring_desc_t; > +typedef struct vring_avail __attribute__((aligned(VRING_AVAIL_ALIGN_SIZE))) > + vring_avail_t; > +typedef struct vring_used __attribute__((aligned(VRING_USED_ALIGN_SIZE))) > + vring_used_t; > + > +struct vring { > + unsigned int num; > + > + vring_desc_t *desc; > + > + vring_avail_t *avail; > + > + vring_used_t *used; > +}; > + > static inline void vring_init(struct vring *vr, unsigned int num, void *p, > unsigned long align) > {
Michael S. Tsirkin
2020-Apr-06 13:55 UTC
[PATCH] vhost: force spec specified alignment on types
On Mon, Apr 06, 2020 at 09:34:00PM +0800, Jason Wang wrote:> > On 2020/4/6 ??8:50, Michael S. Tsirkin wrote: > > The ring element addresses are passed between components with different > > alignments assumptions. Thus, if guest/userspace selects a pointer and > > host then gets and dereferences it, we might need to decrease the > > compiler-selected alignment to prevent compiler on the host from > > assuming pointer is aligned. > > > > This actually triggers on ARM with -mabi=apcs-gnu - which is a > > deprecated configuration, but it seems safer to handle this > > generally. > > > > I verified that the produced binary is exactly identical on x86. > > > > Signed-off-by: Michael S. Tsirkin <mst at redhat.com> > > --- > > > > This is my preferred way to handle the ARM incompatibility issues > > (in preference to kconfig hacks). > > I will push this into next now. > > Comments? > > > I'm not sure if it's too late to fix. It would still be still problematic > for the userspace that is using old uapi headers? > > ThanksIt's not a problem in userspace. The problem is when userspace/guest uses 2 byte alignment and passes it to kernel assuming 8 byte alignment. The fix is for host not to make these assumptions.> > > > > drivers/vhost/vhost.h | 6 ++--- > > include/uapi/linux/virtio_ring.h | 41 ++++++++++++++++++++++++-------- > > 2 files changed, 34 insertions(+), 13 deletions(-) > > > > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > > index cc82918158d2..a67bda9792ec 100644 > > --- a/drivers/vhost/vhost.h > > +++ b/drivers/vhost/vhost.h > > @@ -74,9 +74,9 @@ struct vhost_virtqueue { > > /* The actual ring of buffers. */ > > struct mutex mutex; > > unsigned int num; > > - struct vring_desc __user *desc; > > - struct vring_avail __user *avail; > > - struct vring_used __user *used; > > + vring_desc_t __user *desc; > > + vring_avail_t __user *avail; > > + vring_used_t __user *used; > > const struct vhost_iotlb_map *meta_iotlb[VHOST_NUM_ADDRS]; > > struct vhost_desc *descs; > > diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h > > index 559f42e73315..cd6e0b2eaf2f 100644 > > --- a/include/uapi/linux/virtio_ring.h > > +++ b/include/uapi/linux/virtio_ring.h > > @@ -118,16 +118,6 @@ struct vring_used { > > struct vring_used_elem ring[]; > > }; > > -struct vring { > > - unsigned int num; > > - > > - struct vring_desc *desc; > > - > > - struct vring_avail *avail; > > - > > - struct vring_used *used; > > -}; > > - > > /* Alignment requirements for vring elements. > > * When using pre-virtio 1.0 layout, these fall out naturally. > > */ > > @@ -164,6 +154,37 @@ struct vring { > > #define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) > > #define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num]) > > +/* > > + * The ring element addresses are passed between components with different > > + * alignments assumptions. Thus, we might need to decrease the compiler-selected > > + * alignment, and so must use a typedef to make sure the __aligned attribute > > + * actually takes hold: > > + * > > + * https://gcc.gnu.org/onlinedocs//gcc/Common-Type-Attributes.html#Common-Type-Attributes > > + * > > + * When used on a struct, or struct member, the aligned attribute can only > > + * increase the alignment; in order to decrease it, the packed attribute must > > + * be specified as well. When used as part of a typedef, the aligned attribute > > + * can both increase and decrease alignment, and specifying the packed > > + * attribute generates a warning. > > + */ > > +typedef struct vring_desc __attribute__((aligned(VRING_DESC_ALIGN_SIZE))) > > + vring_desc_t; > > +typedef struct vring_avail __attribute__((aligned(VRING_AVAIL_ALIGN_SIZE))) > > + vring_avail_t; > > +typedef struct vring_used __attribute__((aligned(VRING_USED_ALIGN_SIZE))) > > + vring_used_t; > > + > > +struct vring { > > + unsigned int num; > > + > > + vring_desc_t *desc; > > + > > + vring_avail_t *avail; > > + > > + vring_used_t *used; > > +}; > > + > > static inline void vring_init(struct vring *vr, unsigned int num, void *p, > > unsigned long align) > > {
Reasonably Related Threads
- [PATCH] vhost: force spec specified alignment on types
- [PATCH] vhost: force spec specified alignment on types
- [PATCH] vhost: force spec specified alignment on types
- [PATCH] vhost: force spec specified alignment on types
- [PATCH] vhost: force spec specified alignment on types