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) > > {
On 2020/4/6 ??9:55, Michael S. Tsirkin wrote:> 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? >> >> Thanks > It'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.Yes, but I meant when userspace is complied with apcs-gnu, then it still assumes 8 byte alignment? 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 14:34 UTC
[PATCH] vhost: force spec specified alignment on types
On Mon, Apr 06, 2020 at 10:09:27PM +0800, Jason Wang wrote:> > On 2020/4/6 ??9:55, Michael S. Tsirkin wrote: > > 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? > > > > > > Thanks > > It'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. > > > Yes, but I meant when userspace is complied with apcs-gnu, then it still > assumes 8 byte alignment? > > ThanksThat's not a problem since with vhost userspace is doing the allocation. So it can increase alignment with no bad effect. I agree it's probably safest not to touch struct vring at all though.> > > > > > > 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) > > > > {
Seemingly Similar 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