diff mbox series

drm: Fix alignment of temporary stack ioctl buffers

Message ID 20240611093441.200910-1-carsten.haitzler@foss.arm.com (mailing list archive)
State New, archived
Headers show
Series drm: Fix alignment of temporary stack ioctl buffers | expand

Commit Message

Carsten Haitzler June 11, 2024, 9:34 a.m. UTC
From: Carsten Haitzler <carsten.haitzler@foss.arm.com>

In a few places (core drm + AMD kfd driver), the ioctl handling uses a
temporary 128 byte buffer on the stack to copy to/from user. ioctl data
can have structs with types of much larger sizes than a byte and a
system may require alignment of types in these. At the same time the
compiler may align a char buf to something else as it has no idea that
this buffer is used for storing structs with such alignment
requirements. At a minimum putting in alignment information as an
attribute should be a warning in future if an architecture that needs
more alignment appears.

This was discovered while implementing capability ABI support in Linux
on ARM's Morello CPU (128 bit capability "pointers" in userspace, with
a 64bit non-capability kernel (hybrid) setup). In this, userspace
ioctl structs now had to transport capabilities that needed 16 byte
alignment, but the kernel was not putting these data buffers on that
alignment boundary.

Currently the largest type that is needed is a u64 so the alignment
only asks for that.

Signed-off-by: Carsten Haitzler <carsten.haitzler@foss.arm.com>
---
 drivers/dma-buf/dma-heap.c               | 2 +-
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +-
 drivers/gpu/drm/drm_ioctl.c              | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

Comments

T.J. Mercier June 11, 2024, 4:17 p.m. UTC | #1
On Tue, Jun 11, 2024 at 2:35 AM <carsten.haitzler@foss.arm.com> wrote:
>
> From: Carsten Haitzler <carsten.haitzler@foss.arm.com>
>
> In a few places (core drm + AMD kfd driver), the ioctl handling uses a
> temporary 128 byte buffer on the stack to copy to/from user. ioctl data
> can have structs with types of much larger sizes than a byte and a
> system may require alignment of types in these. At the same time the
> compiler may align a char buf to something else as it has no idea that
> this buffer is used for storing structs with such alignment
> requirements. At a minimum putting in alignment information as an
> attribute should be a warning in future if an architecture that needs
> more alignment appears.
>
> This was discovered while implementing capability ABI support in Linux
> on ARM's Morello CPU (128 bit capability "pointers" in userspace, with
> a 64bit non-capability kernel (hybrid) setup). In this, userspace
> ioctl structs now had to transport capabilities that needed 16 byte
> alignment, but the kernel was not putting these data buffers on that
> alignment boundary.
>
> Currently the largest type that is needed is a u64 so the alignment
> only asks for that.

Makes sense to me.

Now that the kernel depends on C11, I think:
__attribute__((aligned(__alignof__(u64))))

can be simply reduced to:
_Alignas(u64)

and put first instead of last in the declaration:
_Alignas(u64) char stack_kdata[128];

>
> Signed-off-by: Carsten Haitzler <carsten.haitzler@foss.arm.com>
> ---
>  drivers/dma-buf/dma-heap.c               | 2 +-
>  drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +-
>  drivers/gpu/drm/drm_ioctl.c              | 2 +-
>  3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> index 84ae708fafe7..a49e20440edf 100644
> --- a/drivers/dma-buf/dma-heap.c
> +++ b/drivers/dma-buf/dma-heap.c
> @@ -126,7 +126,7 @@ static unsigned int dma_heap_ioctl_cmds[] = {
>  static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
>                            unsigned long arg)
>  {
> -       char stack_kdata[128];
> +       char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
>         char *kdata = stack_kdata;
>         unsigned int kcmd;
>         unsigned int in_size, out_size, drv_size, ksize;
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> index fdf171ad4a3c..69a0aae0f016 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> @@ -3236,7 +3236,7 @@ static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
>         amdkfd_ioctl_t *func;
>         const struct amdkfd_ioctl_desc *ioctl = NULL;
>         unsigned int nr = _IOC_NR(cmd);
> -       char stack_kdata[128];
> +       char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
>         char *kdata = NULL;
>         unsigned int usize, asize;
>         int retcode = -EINVAL;
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index e368fc084c77..aac3d5a539a6 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -767,7 +767,7 @@ long drm_ioctl(struct file *filp,
>         drm_ioctl_t *func;
>         unsigned int nr = DRM_IOCTL_NR(cmd);
>         int retcode = -EINVAL;
> -       char stack_kdata[128];
> +       char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
>         char *kdata = NULL;
>         unsigned int in_size, out_size, drv_size, ksize;
>         bool is_driver_ioctl;
> --
> 2.25.1
>
Carsten Haitzler June 14, 2024, 10:39 a.m. UTC | #2
On 6/11/24 5:17 PM, T.J. Mercier wrote:
> On Tue, Jun 11, 2024 at 2:35 AM <carsten.haitzler@foss.arm.com> wrote:
>>
>> From: Carsten Haitzler <carsten.haitzler@foss.arm.com>
>>
>> In a few places (core drm + AMD kfd driver), the ioctl handling uses a
>> temporary 128 byte buffer on the stack to copy to/from user. ioctl data
>> can have structs with types of much larger sizes than a byte and a
>> system may require alignment of types in these. At the same time the
>> compiler may align a char buf to something else as it has no idea that
>> this buffer is used for storing structs with such alignment
>> requirements. At a minimum putting in alignment information as an
>> attribute should be a warning in future if an architecture that needs
>> more alignment appears.
>>
>> This was discovered while implementing capability ABI support in Linux
>> on ARM's Morello CPU (128 bit capability "pointers" in userspace, with
>> a 64bit non-capability kernel (hybrid) setup). In this, userspace
>> ioctl structs now had to transport capabilities that needed 16 byte
>> alignment, but the kernel was not putting these data buffers on that
>> alignment boundary.
>>
>> Currently the largest type that is needed is a u64 so the alignment
>> only asks for that.
> 
> Makes sense to me.
> 
> Now that the kernel depends on C11, I think:
> __attribute__((aligned(__alignof__(u64))))

Aaaah yes. I'm living in the past as usual. :)

> can be simply reduced to:
> _Alignas(u64)
> 
> and put first instead of last in the declaration:
> _Alignas(u64) char stack_kdata[128];

Yup. Will do. Expect a V2 to come in.

>>
>> Signed-off-by: Carsten Haitzler <carsten.haitzler@foss.arm.com>
>> ---
>>   drivers/dma-buf/dma-heap.c               | 2 +-
>>   drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +-
>>   drivers/gpu/drm/drm_ioctl.c              | 2 +-
>>   3 files changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
>> index 84ae708fafe7..a49e20440edf 100644
>> --- a/drivers/dma-buf/dma-heap.c
>> +++ b/drivers/dma-buf/dma-heap.c
>> @@ -126,7 +126,7 @@ static unsigned int dma_heap_ioctl_cmds[] = {
>>   static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
>>                             unsigned long arg)
>>   {
>> -       char stack_kdata[128];
>> +       char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
>>          char *kdata = stack_kdata;
>>          unsigned int kcmd;
>>          unsigned int in_size, out_size, drv_size, ksize;
>> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> index fdf171ad4a3c..69a0aae0f016 100644
>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> @@ -3236,7 +3236,7 @@ static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
>>          amdkfd_ioctl_t *func;
>>          const struct amdkfd_ioctl_desc *ioctl = NULL;
>>          unsigned int nr = _IOC_NR(cmd);
>> -       char stack_kdata[128];
>> +       char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
>>          char *kdata = NULL;
>>          unsigned int usize, asize;
>>          int retcode = -EINVAL;
>> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
>> index e368fc084c77..aac3d5a539a6 100644
>> --- a/drivers/gpu/drm/drm_ioctl.c
>> +++ b/drivers/gpu/drm/drm_ioctl.c
>> @@ -767,7 +767,7 @@ long drm_ioctl(struct file *filp,
>>          drm_ioctl_t *func;
>>          unsigned int nr = DRM_IOCTL_NR(cmd);
>>          int retcode = -EINVAL;
>> -       char stack_kdata[128];
>> +       char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
>>          char *kdata = NULL;
>>          unsigned int in_size, out_size, drv_size, ksize;
>>          bool is_driver_ioctl;
>> --
>> 2.25.1
>>
diff mbox series

Patch

diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
index 84ae708fafe7..a49e20440edf 100644
--- a/drivers/dma-buf/dma-heap.c
+++ b/drivers/dma-buf/dma-heap.c
@@ -126,7 +126,7 @@  static unsigned int dma_heap_ioctl_cmds[] = {
 static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
 			   unsigned long arg)
 {
-	char stack_kdata[128];
+	char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
 	char *kdata = stack_kdata;
 	unsigned int kcmd;
 	unsigned int in_size, out_size, drv_size, ksize;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index fdf171ad4a3c..69a0aae0f016 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -3236,7 +3236,7 @@  static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 	amdkfd_ioctl_t *func;
 	const struct amdkfd_ioctl_desc *ioctl = NULL;
 	unsigned int nr = _IOC_NR(cmd);
-	char stack_kdata[128];
+	char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
 	char *kdata = NULL;
 	unsigned int usize, asize;
 	int retcode = -EINVAL;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index e368fc084c77..aac3d5a539a6 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -767,7 +767,7 @@  long drm_ioctl(struct file *filp,
 	drm_ioctl_t *func;
 	unsigned int nr = DRM_IOCTL_NR(cmd);
 	int retcode = -EINVAL;
-	char stack_kdata[128];
+	char stack_kdata[128] __attribute__((aligned(__alignof__(u64))));
 	char *kdata = NULL;
 	unsigned int in_size, out_size, drv_size, ksize;
 	bool is_driver_ioctl;