* [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
@ 2026-03-01 12:34 Julian Orth
2026-03-02 11:27 ` Christian König
` (2 more replies)
0 siblings, 3 replies; 36+ messages in thread
From: Julian Orth @ 2026-03-01 12:34 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Christian König, Dmitry Osipenko, Rob Clark
Cc: dri-devel, linux-kernel, Julian Orth
Consider the following application:
#include <fcntl.h>
#include <string.h>
#include <drm/drm.h>
#include <sys/ioctl.h>
int main(void) {
int fd = open("/dev/dri/renderD128", O_RDWR);
struct drm_syncobj_create arg1;
ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
struct drm_syncobj_handle arg2;
memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
arg2.handle = arg1.handle;
arg2.flags = 0;
arg2.fd = 0;
arg2.pad = 0;
// arg2.point = 0; // userspace is required to set point to 0
ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
}
The last ioctl returns EINVAL because args->point is not 0. However,
userspace developed against older kernel versions is not aware of the
new point field and might therefore not initialize it.
The correct check would be
if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
return -EINVAL;
However, there might already be userspace that relies on this not
returning an error as long as point == 0. Therefore use the more lenient
check.
Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
This patch fixes a regression that would cause conversions between
syncobj handles and fds to fail if userspace did not initialize a
recently-added field to 0.
---
drivers/gpu/drm/drm_syncobj.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 250734dee928..49eccb43ce63 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -875,7 +875,7 @@ drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
return drm_syncobj_export_sync_file(file_private, args->handle,
point, &args->fd);
- if (args->point)
+ if (point)
return -EINVAL;
return drm_syncobj_handle_to_fd(file_private, args->handle,
@@ -909,7 +909,7 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
args->handle,
point);
- if (args->point)
+ if (point)
return -EINVAL;
return drm_syncobj_fd_to_handle(file_private, args->fd,
---
base-commit: eb71ab2bf72260054677e348498ba995a057c463
change-id: 20260301-point-4305b6417f55
Best regards,
--
Julian Orth <ju.orth@gmail.com>
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-01 12:34 [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack Julian Orth
@ 2026-03-02 11:27 ` Christian König
2026-03-02 11:54 ` Dmitry Osipenko
2026-03-03 11:17 ` Michel Dänzer
2026-03-03 14:53 ` Maarten Lankhorst
2 siblings, 1 reply; 36+ messages in thread
From: Christian König @ 2026-03-02 11:27 UTC (permalink / raw)
To: Julian Orth, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark
Cc: dri-devel, linux-kernel
On 3/1/26 13:34, Julian Orth wrote:
> Consider the following application:
>
> #include <fcntl.h>
> #include <string.h>
> #include <drm/drm.h>
> #include <sys/ioctl.h>
>
> int main(void) {
> int fd = open("/dev/dri/renderD128", O_RDWR);
> struct drm_syncobj_create arg1;
> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
> struct drm_syncobj_handle arg2;
> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
> arg2.handle = arg1.handle;
> arg2.flags = 0;
> arg2.fd = 0;
> arg2.pad = 0;
> // arg2.point = 0; // userspace is required to set point to 0
> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
> }
>
> The last ioctl returns EINVAL because args->point is not 0. However,
> userspace developed against older kernel versions is not aware of the
> new point field and might therefore not initialize it.
>
> The correct check would be
>
> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
> return -EINVAL;
>
> However, there might already be userspace that relies on this not
> returning an error as long as point == 0. Therefore use the more lenient
> check.
>
> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
> Signed-off-by: Julian Orth <ju.orth@gmail.com>
Good catch, Reviewed-by: Christian König <christian.koenig@amd.com>
As long as nobody objects I'm going to push this to drm-misc-fixes later today.
Thanks,
Christian.
> ---
> This patch fixes a regression that would cause conversions between
> syncobj handles and fds to fail if userspace did not initialize a
> recently-added field to 0.
> ---
> drivers/gpu/drm/drm_syncobj.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
> index 250734dee928..49eccb43ce63 100644
> --- a/drivers/gpu/drm/drm_syncobj.c
> +++ b/drivers/gpu/drm/drm_syncobj.c
> @@ -875,7 +875,7 @@ drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
> return drm_syncobj_export_sync_file(file_private, args->handle,
> point, &args->fd);
>
> - if (args->point)
> + if (point)
> return -EINVAL;
>
> return drm_syncobj_handle_to_fd(file_private, args->handle,
> @@ -909,7 +909,7 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
> args->handle,
> point);
>
> - if (args->point)
> + if (point)
> return -EINVAL;
>
> return drm_syncobj_fd_to_handle(file_private, args->fd,
>
> ---
> base-commit: eb71ab2bf72260054677e348498ba995a057c463
> change-id: 20260301-point-4305b6417f55
>
> Best regards,
> --
> Julian Orth <ju.orth@gmail.com>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-02 11:27 ` Christian König
@ 2026-03-02 11:54 ` Dmitry Osipenko
0 siblings, 0 replies; 36+ messages in thread
From: Dmitry Osipenko @ 2026-03-02 11:54 UTC (permalink / raw)
To: Christian König, Julian Orth, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Rob Clark
Cc: dri-devel, linux-kernel
On 3/2/26 14:27, Christian König wrote:
> On 3/1/26 13:34, Julian Orth wrote:
>> Consider the following application:
>>
>> #include <fcntl.h>
>> #include <string.h>
>> #include <drm/drm.h>
>> #include <sys/ioctl.h>
>>
>> int main(void) {
>> int fd = open("/dev/dri/renderD128", O_RDWR);
>> struct drm_syncobj_create arg1;
>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
>> struct drm_syncobj_handle arg2;
>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
>> arg2.handle = arg1.handle;
>> arg2.flags = 0;
>> arg2.fd = 0;
>> arg2.pad = 0;
>> // arg2.point = 0; // userspace is required to set point to 0
>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
>> }
>>
>> The last ioctl returns EINVAL because args->point is not 0. However,
>> userspace developed against older kernel versions is not aware of the
>> new point field and might therefore not initialize it.
>>
>> The correct check would be
>>
>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
>> return -EINVAL;
>>
>> However, there might already be userspace that relies on this not
>> returning an error as long as point == 0. Therefore use the more lenient
>> check.
>>
>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
>
> Good catch, Reviewed-by: Christian König <christian.koenig@amd.com>
>
> As long as nobody objects I'm going to push this to drm-misc-fixes later today.
No objections, thanks
--
Best regards,
Dmitry
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-01 12:34 [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack Julian Orth
2026-03-02 11:27 ` Christian König
@ 2026-03-03 11:17 ` Michel Dänzer
2026-03-03 11:23 ` Julian Orth
2026-03-03 14:53 ` Maarten Lankhorst
2 siblings, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 11:17 UTC (permalink / raw)
To: Julian Orth, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Christian König,
Dmitry Osipenko, Rob Clark
Cc: dri-devel, linux-kernel
On 3/1/26 13:34, Julian Orth wrote:
> Consider the following application:
>
> #include <fcntl.h>
> #include <string.h>
> #include <drm/drm.h>
> #include <sys/ioctl.h>
>
> int main(void) {
> int fd = open("/dev/dri/renderD128", O_RDWR);
> struct drm_syncobj_create arg1;
> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
> struct drm_syncobj_handle arg2;
> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
> arg2.handle = arg1.handle;
> arg2.flags = 0;
> arg2.fd = 0;
> arg2.pad = 0;
> // arg2.point = 0; // userspace is required to set point to 0
> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
> }
>
> The last ioctl returns EINVAL because args->point is not 0. However,
> userspace developed against older kernel versions is not aware of the
> new point field and might therefore not initialize it.
>
> The correct check would be
>
> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
> return -EINVAL;
>
> However, there might already be userspace that relies on this not
> returning an error as long as point == 0. Therefore use the more lenient
> check.
>
> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
> Signed-off-by: Julian Orth <ju.orth@gmail.com>
> ---
> This patch fixes a regression that would cause conversions between
> syncobj handles and fds to fail if userspace did not initialize a
> recently-added field to 0.
While I don't object to this change, I'd argue that this is really a workaround for broken user space, not a fix for a kernel regression.
User space must initialize the full struct to 0, except for the fields it wants to have other values. This kind of kernel-side workaround for neglecting that won't be possible in all cases.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 11:17 ` Michel Dänzer
@ 2026-03-03 11:23 ` Julian Orth
2026-03-03 11:38 ` Michel Dänzer
0 siblings, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-03 11:23 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Christian König, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 12:17 PM Michel Dänzer
<michel.daenzer@mailbox.org> wrote:
>
> While I don't object to this change, I'd argue that this is really a workaround for broken user space, not a fix for a kernel regression.
>
> User space must initialize the full struct to 0, except for the fields it wants to have other values. This kind of kernel-side workaround for neglecting that won't be possible in all cases.
When the code in my example was written, the points field did not
exist. Therefore, as far as that code is concerned, the authors
believed that the struct was fully initialized, since they manually
initialized all fields that were contained in the struct at that time.
The code was then later recompiled against a version of drm/drm.h that
contained the new field.
Or are you saying that userspace must always use memset(&arg, 0,
sizeof(arg)) to initialize ioctl arguments? If so, ioctl(2) does not
mention this.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 11:23 ` Julian Orth
@ 2026-03-03 11:38 ` Michel Dänzer
2026-03-03 11:41 ` Julian Orth
0 siblings, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 11:38 UTC (permalink / raw)
To: Julian Orth
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Christian König, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On 3/3/26 12:23, Julian Orth wrote:
> On Tue, Mar 3, 2026 at 12:17 PM Michel Dänzer
> <michel.daenzer@mailbox.org> wrote:
>>
>> While I don't object to this change, I'd argue that this is really a workaround for broken user space, not a fix for a kernel regression.
>>
>> User space must initialize the full struct to 0, except for the fields it wants to have other values. This kind of kernel-side workaround for neglecting that won't be possible in all cases.
>
> When the code in my example was written, the points field did not
> exist. Therefore, as far as that code is concerned, the authors
> believed that the struct was fully initialized, since they manually
> initialized all fields that were contained in the struct at that time.
> The code was then later recompiled against a version of drm/drm.h that
> contained the new field.
>
> Or are you saying that userspace must always use memset(&arg, 0,
> sizeof(arg)) to initialize ioctl arguments?
Yes, it must. Any approach which results in newly-added fields not being initialized to 0 is broken.
To prevent a potential follow-up concern: What if the kernel uses a larger size of the struct than user space? That's fine, user space encodes the size it uses in the parameters to the ioctl system call, and the kernel uses 0 for all fields beyond that size.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 11:38 ` Michel Dänzer
@ 2026-03-03 11:41 ` Julian Orth
0 siblings, 0 replies; 36+ messages in thread
From: Julian Orth @ 2026-03-03 11:41 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Christian König, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 12:38 PM Michel Dänzer
<michel.daenzer@mailbox.org> wrote:
>
> On 3/3/26 12:23, Julian Orth wrote:
> > On Tue, Mar 3, 2026 at 12:17 PM Michel Dänzer
> > <michel.daenzer@mailbox.org> wrote:
> >>
> >> While I don't object to this change, I'd argue that this is really a workaround for broken user space, not a fix for a kernel regression.
> >>
> >> User space must initialize the full struct to 0, except for the fields it wants to have other values. This kind of kernel-side workaround for neglecting that won't be possible in all cases.
> >
> > When the code in my example was written, the points field did not
> > exist. Therefore, as far as that code is concerned, the authors
> > believed that the struct was fully initialized, since they manually
> > initialized all fields that were contained in the struct at that time.
> > The code was then later recompiled against a version of drm/drm.h that
> > contained the new field.
> >
> > Or are you saying that userspace must always use memset(&arg, 0,
> > sizeof(arg)) to initialize ioctl arguments?
>
> Yes, it must. Any approach which results in newly-added fields not being initialized to 0 is broken.
Do you know of any other case where access to the new fields is not
guarded by some kind of flag that exists in all versions of the
struct?
>
>
> To prevent a potential follow-up concern: What if the kernel uses a larger size of the struct than user space? That's fine, user space encodes the size it uses in the parameters to the ioctl system call, and the kernel uses 0 for all fields beyond that size.
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-01 12:34 [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack Julian Orth
2026-03-02 11:27 ` Christian König
2026-03-03 11:17 ` Michel Dänzer
@ 2026-03-03 14:53 ` Maarten Lankhorst
2026-03-03 14:59 ` Christian König
2 siblings, 1 reply; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-03 14:53 UTC (permalink / raw)
To: Julian Orth, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Christian König, Dmitry Osipenko, Rob Clark
Cc: dri-devel, linux-kernel
Hey,
Den 2026-03-01 kl. 13:34, skrev Julian Orth:
> Consider the following application:
>
> #include <fcntl.h>
> #include <string.h>
> #include <drm/drm.h>
> #include <sys/ioctl.h>
>
> int main(void) {
> int fd = open("/dev/dri/renderD128", O_RDWR);
> struct drm_syncobj_create arg1;
> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
> struct drm_syncobj_handle arg2;
> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
> arg2.handle = arg1.handle;
> arg2.flags = 0;
> arg2.fd = 0;
> arg2.pad = 0;
> // arg2.point = 0; // userspace is required to set point to 0
> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
> }
>
> The last ioctl returns EINVAL because args->point is not 0. However,
> userspace developed against older kernel versions is not aware of the
> new point field and might therefore not initialize it.
>
> The correct check would be
>
> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
> return -EINVAL;
>
> However, there might already be userspace that relies on this not
> returning an error as long as point == 0. Therefore use the more lenient
> check.
>
> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
> Signed-off-by: Julian Orth <ju.orth@gmail.com>
I'm not convinced this is the correct fix.
Userspace built before the change had the old size for drm_syncobj_create,
the size is encoded into the ioctl, and zero extended as needed.
See drivers/gpu/drm/drm_ioctl.c:
out_size = in_size = _IOC_SIZE(cmd);
...
if (ksize > in_size)
memset(kdata + in_size, 0, ksize - in_size);
This is a bug in a newly built app, and should be handled by explicitly zeroing
the entire struct or using named initializers, and only setting specific members
as required.
In particular, apps built before the change will never encounter this bug.
Kind regards,
~Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 14:53 ` Maarten Lankhorst
@ 2026-03-03 14:59 ` Christian König
2026-03-03 15:15 ` Maarten Lankhorst
2026-03-03 15:29 ` Michel Dänzer
0 siblings, 2 replies; 36+ messages in thread
From: Christian König @ 2026-03-03 14:59 UTC (permalink / raw)
To: Maarten Lankhorst, Julian Orth, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark
Cc: dri-devel, linux-kernel
On 3/3/26 15:53, Maarten Lankhorst wrote:
> Hey,
>
> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
>> Consider the following application:
>>
>> #include <fcntl.h>
>> #include <string.h>
>> #include <drm/drm.h>
>> #include <sys/ioctl.h>
>>
>> int main(void) {
>> int fd = open("/dev/dri/renderD128", O_RDWR);
>> struct drm_syncobj_create arg1;
>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
>> struct drm_syncobj_handle arg2;
>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
>> arg2.handle = arg1.handle;
>> arg2.flags = 0;
>> arg2.fd = 0;
>> arg2.pad = 0;
>> // arg2.point = 0; // userspace is required to set point to 0
>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
>> }
>>
>> The last ioctl returns EINVAL because args->point is not 0. However,
>> userspace developed against older kernel versions is not aware of the
>> new point field and might therefore not initialize it.
>>
>> The correct check would be
>>
>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
>> return -EINVAL;
>>
>> However, there might already be userspace that relies on this not
>> returning an error as long as point == 0. Therefore use the more lenient
>> check.
>>
>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
>
> I'm not convinced this is the correct fix.
> Userspace built before the change had the old size for drm_syncobj_create,
> the size is encoded into the ioctl, and zero extended as needed.
>
> See drivers/gpu/drm/drm_ioctl.c:
> out_size = in_size = _IOC_SIZE(cmd);
> ...
> if (ksize > in_size)
> memset(kdata + in_size, 0, ksize - in_size);
>
> This is a bug in a newly built app, and should be handled by explicitly zeroing
> the entire struct or using named initializers, and only setting specific members
> as required.
>
> In particular, apps built before the change will never encounter this bug.
Yeah, I've realized that after pushing the patch as well.
But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
Regards,
Christian.
>
> Kind regards,
> ~Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 14:59 ` Christian König
@ 2026-03-03 15:15 ` Maarten Lankhorst
2026-03-03 15:21 ` Julian Orth
2026-03-03 15:29 ` Michel Dänzer
1 sibling, 1 reply; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-03 15:15 UTC (permalink / raw)
To: Christian König, Julian Orth, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark
Cc: dri-devel, linux-kernel
Hey,
Den 2026-03-03 kl. 15:59, skrev Christian König:
> On 3/3/26 15:53, Maarten Lankhorst wrote:
>> Hey,
>>
>> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
>>> Consider the following application:
>>>
>>> #include <fcntl.h>
>>> #include <string.h>
>>> #include <drm/drm.h>
>>> #include <sys/ioctl.h>
>>>
>>> int main(void) {
>>> int fd = open("/dev/dri/renderD128", O_RDWR);
>>> struct drm_syncobj_create arg1;
>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
>>> struct drm_syncobj_handle arg2;
>>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
>>> arg2.handle = arg1.handle;
>>> arg2.flags = 0;
>>> arg2.fd = 0;
>>> arg2.pad = 0;
>>> // arg2.point = 0; // userspace is required to set point to 0
>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
>>> }
>>>
>>> The last ioctl returns EINVAL because args->point is not 0. However,
>>> userspace developed against older kernel versions is not aware of the
>>> new point field and might therefore not initialize it.
>>>
>>> The correct check would be
>>>
>>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
>>> return -EINVAL;
>>>
>>> However, there might already be userspace that relies on this not
>>> returning an error as long as point == 0. Therefore use the more lenient
>>> check.
>>>
>>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
>>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
>>
>> I'm not convinced this is the correct fix.
>> Userspace built before the change had the old size for drm_syncobj_create,
>> the size is encoded into the ioctl, and zero extended as needed.
>>
>> See drivers/gpu/drm/drm_ioctl.c:
>> out_size = in_size = _IOC_SIZE(cmd);
>> ...
>> if (ksize > in_size)
>> memset(kdata + in_size, 0, ksize - in_size);
>>
>> This is a bug in a newly built app, and should be handled by explicitly zeroing
>> the entire struct or using named initializers, and only setting specific members
>> as required.
>>
>> In particular, apps built before the change will never encounter this bug.
>
> Yeah, I've realized that after pushing the patch as well.
>
> But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
>
> And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
>
> It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
I know that in case of xe, even padding members are tested for being zero. For new code it's
explicitly recommended to test to prevent running into undefined behavior. In some cases
data may look valid, even if it's just random garbage from the stack.
Is it too late to revert?
Kind regards,
Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 15:15 ` Maarten Lankhorst
@ 2026-03-03 15:21 ` Julian Orth
2026-03-03 17:02 ` Michel Dänzer
0 siblings, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-03 15:21 UTC (permalink / raw)
To: Maarten Lankhorst
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 4:15 PM Maarten Lankhorst
<maarten.lankhorst@linux.intel.com> wrote:
>
> Hey,
>
> Den 2026-03-03 kl. 15:59, skrev Christian König:
> > On 3/3/26 15:53, Maarten Lankhorst wrote:
> >> Hey,
> >>
> >> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
> >>> Consider the following application:
> >>>
> >>> #include <fcntl.h>
> >>> #include <string.h>
> >>> #include <drm/drm.h>
> >>> #include <sys/ioctl.h>
> >>>
> >>> int main(void) {
> >>> int fd = open("/dev/dri/renderD128", O_RDWR);
> >>> struct drm_syncobj_create arg1;
> >>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
> >>> struct drm_syncobj_handle arg2;
> >>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
> >>> arg2.handle = arg1.handle;
> >>> arg2.flags = 0;
> >>> arg2.fd = 0;
> >>> arg2.pad = 0;
> >>> // arg2.point = 0; // userspace is required to set point to 0
> >>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
> >>> }
> >>>
> >>> The last ioctl returns EINVAL because args->point is not 0. However,
> >>> userspace developed against older kernel versions is not aware of the
> >>> new point field and might therefore not initialize it.
> >>>
> >>> The correct check would be
> >>>
> >>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
> >>> return -EINVAL;
> >>>
> >>> However, there might already be userspace that relies on this not
> >>> returning an error as long as point == 0. Therefore use the more lenient
> >>> check.
> >>>
> >>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
> >>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
> >>
> >> I'm not convinced this is the correct fix.
> >> Userspace built before the change had the old size for drm_syncobj_create,
> >> the size is encoded into the ioctl, and zero extended as needed.
> >>
> >> See drivers/gpu/drm/drm_ioctl.c:
> >> out_size = in_size = _IOC_SIZE(cmd);
> >> ...
> >> if (ksize > in_size)
> >> memset(kdata + in_size, 0, ksize - in_size);
> >>
> >> This is a bug in a newly built app, and should be handled by explicitly zeroing
> >> the entire struct or using named initializers, and only setting specific members
> >> as required.
> >>
> >> In particular, apps built before the change will never encounter this bug.
> >
> > Yeah, I've realized that after pushing the patch as well.
> >
> > But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
> >
> > And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
> >
> > It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
> I know that in case of xe, even padding members are tested for being zero. For new code it's
> explicitly recommended to test to prevent running into undefined behavior. In some cases
> data may look valid, even if it's just random garbage from the stack.
This isn't about padding fields. This is about a new field that was
added to the struct, increasing its size. Existing code could not have
zero-initialized that field except by using memset or something
equivalent. As long as the requirement to use memset is not
documented, requiring existing code to use memset is a breaking change
because code that didn't use memset always worked until the new field
was added.
>
> Is it too late to revert?
>
> Kind regards,
> Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 14:59 ` Christian König
2026-03-03 15:15 ` Maarten Lankhorst
@ 2026-03-03 15:29 ` Michel Dänzer
2026-03-03 15:36 ` Julian Orth
1 sibling, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 15:29 UTC (permalink / raw)
To: Christian König, Maarten Lankhorst, Julian Orth,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Dmitry Osipenko, Rob Clark
Cc: dri-devel, linux-kernel
On 3/3/26 15:59, Christian König wrote:
> On 3/3/26 15:53, Maarten Lankhorst wrote:
>> Hey,
>>
>> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
>>> Consider the following application:
>>>
>>> #include <fcntl.h>
>>> #include <string.h>
>>> #include <drm/drm.h>
>>> #include <sys/ioctl.h>
>>>
>>> int main(void) {
>>> int fd = open("/dev/dri/renderD128", O_RDWR);
>>> struct drm_syncobj_create arg1;
>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
>>> struct drm_syncobj_handle arg2;
>>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
>>> arg2.handle = arg1.handle;
>>> arg2.flags = 0;
>>> arg2.fd = 0;
>>> arg2.pad = 0;
>>> // arg2.point = 0; // userspace is required to set point to 0
>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
>>> }
>>>
>>> The last ioctl returns EINVAL because args->point is not 0. However,
>>> userspace developed against older kernel versions is not aware of the
>>> new point field and might therefore not initialize it.
>>>
>>> The correct check would be
>>>
>>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
>>> return -EINVAL;
>>>
>>> However, there might already be userspace that relies on this not
>>> returning an error as long as point == 0. Therefore use the more lenient
>>> check.
>>>
>>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
>>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
>>
>> I'm not convinced this is the correct fix.
>> Userspace built before the change had the old size for drm_syncobj_create,
>> the size is encoded into the ioctl, and zero extended as needed.
>>
>> See drivers/gpu/drm/drm_ioctl.c:
>> out_size = in_size = _IOC_SIZE(cmd);
>> ...
>> if (ksize > in_size)
>> memset(kdata + in_size, 0, ksize - in_size);
>>
>> This is a bug in a newly built app, and should be handled by explicitly zeroing
>> the entire struct or using named initializers, and only setting specific members
>> as required.
>>
>> In particular, apps built before the change will never encounter this bug.
>
> Yeah, I've realized that after pushing the patch as well.
>
> But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
>
> And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
>
> It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
Even though it may not be documented, it is in fact mandatory. Otherwise it's not possible to safely extend ioctl structs in general.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 15:29 ` Michel Dänzer
@ 2026-03-03 15:36 ` Julian Orth
2026-03-03 16:40 ` Maarten Lankhorst
0 siblings, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-03 15:36 UTC (permalink / raw)
To: Michel Dänzer
Cc: Christian König, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 4:29 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>
> On 3/3/26 15:59, Christian König wrote:
> > On 3/3/26 15:53, Maarten Lankhorst wrote:
> >> Hey,
> >>
> >> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
> >>> Consider the following application:
> >>>
> >>> #include <fcntl.h>
> >>> #include <string.h>
> >>> #include <drm/drm.h>
> >>> #include <sys/ioctl.h>
> >>>
> >>> int main(void) {
> >>> int fd = open("/dev/dri/renderD128", O_RDWR);
> >>> struct drm_syncobj_create arg1;
> >>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
> >>> struct drm_syncobj_handle arg2;
> >>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
> >>> arg2.handle = arg1.handle;
> >>> arg2.flags = 0;
> >>> arg2.fd = 0;
> >>> arg2.pad = 0;
> >>> // arg2.point = 0; // userspace is required to set point to 0
> >>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
> >>> }
> >>>
> >>> The last ioctl returns EINVAL because args->point is not 0. However,
> >>> userspace developed against older kernel versions is not aware of the
> >>> new point field and might therefore not initialize it.
> >>>
> >>> The correct check would be
> >>>
> >>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
> >>> return -EINVAL;
> >>>
> >>> However, there might already be userspace that relies on this not
> >>> returning an error as long as point == 0. Therefore use the more lenient
> >>> check.
> >>>
> >>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
> >>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
> >>
> >> I'm not convinced this is the correct fix.
> >> Userspace built before the change had the old size for drm_syncobj_create,
> >> the size is encoded into the ioctl, and zero extended as needed.
> >>
> >> See drivers/gpu/drm/drm_ioctl.c:
> >> out_size = in_size = _IOC_SIZE(cmd);
> >> ...
> >> if (ksize > in_size)
> >> memset(kdata + in_size, 0, ksize - in_size);
> >>
> >> This is a bug in a newly built app, and should be handled by explicitly zeroing
> >> the entire struct or using named initializers, and only setting specific members
> >> as required.
> >>
> >> In particular, apps built before the change will never encounter this bug.
> >
> > Yeah, I've realized that after pushing the patch as well.
> >
> > But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
> >
> > And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
> >
> > It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
>
> Even though it may not be documented, it is in fact mandatory. Otherwise it's not possible to safely extend ioctl structs in general.
The intention of the original patch was to ignore the args->points
field if the flag is not set:
if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE)
point = args->point;
Using args->point unconditionally later was therefore a mistake.
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 15:36 ` Julian Orth
@ 2026-03-03 16:40 ` Maarten Lankhorst
2026-03-03 16:54 ` Julian Orth
0 siblings, 1 reply; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-03 16:40 UTC (permalink / raw)
To: Julian Orth, Michel Dänzer
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
Hey,
Den 2026-03-03 kl. 16:36, skrev Julian Orth:
> On Tue, Mar 3, 2026 at 4:29 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>
>> On 3/3/26 15:59, Christian König wrote:
>>> On 3/3/26 15:53, Maarten Lankhorst wrote:
>>>> Hey,
>>>>
>>>> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
>>>>> Consider the following application:
>>>>>
>>>>> #include <fcntl.h>
>>>>> #include <string.h>
>>>>> #include <drm/drm.h>
>>>>> #include <sys/ioctl.h>
>>>>>
>>>>> int main(void) {
>>>>> int fd = open("/dev/dri/renderD128", O_RDWR);
>>>>> struct drm_syncobj_create arg1;
>>>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
>>>>> struct drm_syncobj_handle arg2;
>>>>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
>>>>> arg2.handle = arg1.handle;
>>>>> arg2.flags = 0;
>>>>> arg2.fd = 0;
>>>>> arg2.pad = 0;
>>>>> // arg2.point = 0; // userspace is required to set point to 0
>>>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
>>>>> }
>>>>>
>>>>> The last ioctl returns EINVAL because args->point is not 0. However,
>>>>> userspace developed against older kernel versions is not aware of the
>>>>> new point field and might therefore not initialize it.
>>>>>
>>>>> The correct check would be
>>>>>
>>>>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
>>>>> return -EINVAL;
>>>>>
>>>>> However, there might already be userspace that relies on this not
>>>>> returning an error as long as point == 0. Therefore use the more lenient
>>>>> check.
>>>>>
>>>>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
>>>>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
>>>>
>>>> I'm not convinced this is the correct fix.
>>>> Userspace built before the change had the old size for drm_syncobj_create,
>>>> the size is encoded into the ioctl, and zero extended as needed.
>>>>
>>>> See drivers/gpu/drm/drm_ioctl.c:
>>>> out_size = in_size = _IOC_SIZE(cmd);
>>>> ...
>>>> if (ksize > in_size)
>>>> memset(kdata + in_size, 0, ksize - in_size);
>>>>
>>>> This is a bug in a newly built app, and should be handled by explicitly zeroing
>>>> the entire struct or using named initializers, and only setting specific members
>>>> as required.
>>>>
>>>> In particular, apps built before the change will never encounter this bug.
>>>
>>> Yeah, I've realized that after pushing the patch as well.
>>>
>>> But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
>>>
>>> And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
>>>
>>> It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
>>
>> Even though it may not be documented, it is in fact mandatory. Otherwise it's not possible to safely extend ioctl structs in general.
>
> The intention of the original patch was to ignore the args->points
> field if the flag is not set:
>
> if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE)
> point = args->point;
>
> Using args->point unconditionally later was therefore a mistake.
There is precedence in the ioctl, the pad member is checked against zero for the same reason.
The check was there because it is invalid to pass when IMPORT/EXPORT_SYNC_FILE was not set.
This is what I would recommend instead:
----
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 2d4ab745fdad9..176fac24a3198 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -857,7 +857,6 @@ drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
struct drm_syncobj_handle *args = data;
unsigned int valid_flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE |
DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
- u64 point = 0;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
return -EOPNOTSUPP;
@@ -868,15 +867,14 @@ drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
if (args->flags & ~valid_flags)
return -EINVAL;
- if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE)
- point = args->point;
+ if (!(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE) &&
+ !(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE) &&
+ args->point)
+ return -EINVAL;
if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
return drm_syncobj_export_sync_file(file_private, args->handle,
- point, &args->fd);
-
- if (args->point)
- return -EINVAL;
+ args->point, &args->fd);
return drm_syncobj_handle_to_fd(file_private, args->handle,
&args->fd);
@@ -889,7 +887,6 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
struct drm_syncobj_handle *args = data;
unsigned int valid_flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE |
DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
- u64 point = 0;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
return -EOPNOTSUPP;
@@ -900,17 +897,16 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
if (args->flags & ~valid_flags)
return -EINVAL;
- if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
- point = args->point;
+ if (!(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE) &&
+ !(args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE) &&
+ args->point)
+ return -EINVAL;
if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
return drm_syncobj_import_sync_file_fence(file_private,
args->fd,
args->handle,
- point);
-
- if (args->point)
- return -EINVAL;
+ args->point);
return drm_syncobj_fd_to_handle(file_private, args->fd,
&args->handle);
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 16:40 ` Maarten Lankhorst
@ 2026-03-03 16:54 ` Julian Orth
2026-03-03 17:04 ` Michel Dänzer
2026-03-03 17:05 ` Maarten Lankhorst
0 siblings, 2 replies; 36+ messages in thread
From: Julian Orth @ 2026-03-03 16:54 UTC (permalink / raw)
To: Maarten Lankhorst
Cc: Michel Dänzer, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 5:40 PM Maarten Lankhorst
<maarten.lankhorst@linux.intel.com> wrote:
>
> There is precedence in the ioctl, the pad member is checked against zero for the same reason.
I don't believe that this is comparable. Developers of code developed
against an older kernel could look at the kernel and see that the pad
field was checked against zero. They could not see the same for fields
that didn't exist at the time.
> The check was there because it is invalid to pass when IMPORT/EXPORT_SYNC_FILE was not set.
>
> This is what I would recommend instead:
>
> [...]
>
> + if (!(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE) &&
> + !(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE) &&
> + args->point)
> + return -EINVAL;
Should it not be
+ if ((!(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE) ||
+ !(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)) &&
+ args->point)
+ return -EINVAL;
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 15:21 ` Julian Orth
@ 2026-03-03 17:02 ` Michel Dänzer
0 siblings, 0 replies; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 17:02 UTC (permalink / raw)
To: Julian Orth, Maarten Lankhorst
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On 3/3/26 16:21, Julian Orth wrote:
> On Tue, Mar 3, 2026 at 4:15 PM Maarten Lankhorst
> <maarten.lankhorst@linux.intel.com> wrote:
>>
>> Hey,
>>
>> Den 2026-03-03 kl. 15:59, skrev Christian König:
>>> On 3/3/26 15:53, Maarten Lankhorst wrote:
>>>> Hey,
>>>>
>>>> Den 2026-03-01 kl. 13:34, skrev Julian Orth:
>>>>> Consider the following application:
>>>>>
>>>>> #include <fcntl.h>
>>>>> #include <string.h>
>>>>> #include <drm/drm.h>
>>>>> #include <sys/ioctl.h>
>>>>>
>>>>> int main(void) {
>>>>> int fd = open("/dev/dri/renderD128", O_RDWR);
>>>>> struct drm_syncobj_create arg1;
>>>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &arg1);
>>>>> struct drm_syncobj_handle arg2;
>>>>> memset(&arg2, 1, sizeof(arg2)); // simulate dirty stack
>>>>> arg2.handle = arg1.handle;
>>>>> arg2.flags = 0;
>>>>> arg2.fd = 0;
>>>>> arg2.pad = 0;
>>>>> // arg2.point = 0; // userspace is required to set point to 0
>>>>> ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg2);
>>>>> }
>>>>>
>>>>> The last ioctl returns EINVAL because args->point is not 0. However,
>>>>> userspace developed against older kernel versions is not aware of the
>>>>> new point field and might therefore not initialize it.
>>>>>
>>>>> The correct check would be
>>>>>
>>>>> if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE)
>>>>> return -EINVAL;
>>>>>
>>>>> However, there might already be userspace that relies on this not
>>>>> returning an error as long as point == 0. Therefore use the more lenient
>>>>> check.
>>>>>
>>>>> Fixes: c2d3a7300695 ("drm/syncobj: Extend EXPORT_SYNC_FILE for timeline syncobjs")
>>>>> Signed-off-by: Julian Orth <ju.orth@gmail.com>
>>>>
>>>> I'm not convinced this is the correct fix.
>>>> Userspace built before the change had the old size for drm_syncobj_create,
>>>> the size is encoded into the ioctl, and zero extended as needed.
>>>>
>>>> See drivers/gpu/drm/drm_ioctl.c:
>>>> out_size = in_size = _IOC_SIZE(cmd);
>>>> ...
>>>> if (ksize > in_size)
>>>> memset(kdata + in_size, 0, ksize - in_size);
>>>>
>>>> This is a bug in a newly built app, and should be handled by explicitly zeroing
>>>> the entire struct or using named initializers, and only setting specific members
>>>> as required.
>>>>
>>>> In particular, apps built before the change will never encounter this bug.
>>>
>>> Yeah, I've realized that after pushing the patch as well.
>>>
>>> But I still think this patch is the right thing to do, because without requesting the functionality by setting the flag the point should clearly not have any effect at all.
>>>
>>> And when an application would have only explicitly assigned the fields known previously and then later been compiled with the new points field it would have failed.
>>>
>>> It is good practice to memset() structures given to the kernel so that all bytes are zero initialized, but it is not documented as mandatory as far as I know.
>> I know that in case of xe, even padding members are tested for being zero. For new code it's
>> explicitly recommended to test to prevent running into undefined behavior. In some cases
>> data may look valid, even if it's just random garbage from the stack.
>
> This isn't about padding fields. This is about a new field that was
> added to the struct, increasing its size. Existing code could not have
> zero-initialized that field except by using memset or something
> equivalent. As long as the requirement to use memset is not
> documented, requiring existing code to use memset is a breaking change
> because code that didn't use memset always worked until the new field
> was added.
It's always been effectively mandatory, it's not a breaking change.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 16:54 ` Julian Orth
@ 2026-03-03 17:04 ` Michel Dänzer
2026-03-03 17:11 ` Julian Orth
2026-03-03 17:05 ` Maarten Lankhorst
1 sibling, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 17:04 UTC (permalink / raw)
To: Julian Orth, Maarten Lankhorst
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On 3/3/26 17:54, Julian Orth wrote:
> On Tue, Mar 3, 2026 at 5:40 PM Maarten Lankhorst
> <maarten.lankhorst@linux.intel.com> wrote:
>>
>> There is precedence in the ioctl, the pad member is checked against zero for the same reason.
>
> I don't believe that this is comparable. Developers of code developed
> against an older kernel could look at the kernel and see that the pad
> field was checked against zero. They could not see the same for fields
> that didn't exist at the time.
"Initialize only known fields" isn't a valid approach here. The full struct must be initialized to 0, including any fields added in the future.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 16:54 ` Julian Orth
2026-03-03 17:04 ` Michel Dänzer
@ 2026-03-03 17:05 ` Maarten Lankhorst
1 sibling, 0 replies; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-03 17:05 UTC (permalink / raw)
To: Julian Orth
Cc: Michel Dänzer, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
Hey,
Den 2026-03-03 kl. 17:54, skrev Julian Orth:
> On Tue, Mar 3, 2026 at 5:40 PM Maarten Lankhorst
> <maarten.lankhorst@linux.intel.com> wrote:
>>
>> There is precedence in the ioctl, the pad member is checked against zero for the same reason.
>
> I don't believe that this is comparable. Developers of code developed
> against an older kernel could look at the kernel and see that the pad
> field was checked against zero. They could not see the same for fields
> that didn't exist at the time.
>
>> The check was there because it is invalid to pass when IMPORT/EXPORT_SYNC_FILE was not set.
>>
>> This is what I would recommend instead:
>>
>> [...]
>>
>> + if (!(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE) &&
>> + !(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE) &&
>> + args->point)
>> + return -EINVAL;
>
> Should it not be
>
> + if ((!(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE) ||
> + !(args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)) &&
> + args->point)
> + return -EINVAL;
Yeah copy paste error. :)
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:04 ` Michel Dänzer
@ 2026-03-03 17:11 ` Julian Orth
2026-03-03 17:18 ` Michel Dänzer
0 siblings, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-03 17:11 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 6:04 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>
> On 3/3/26 17:54, Julian Orth wrote:
> > On Tue, Mar 3, 2026 at 5:40 PM Maarten Lankhorst
> > <maarten.lankhorst@linux.intel.com> wrote:
> >>
> >> There is precedence in the ioctl, the pad member is checked against zero for the same reason.
> >
> > I don't believe that this is comparable. Developers of code developed
> > against an older kernel could look at the kernel and see that the pad
> > field was checked against zero. They could not see the same for fields
> > that didn't exist at the time.
>
> "Initialize only known fields" isn't a valid approach here. The full struct must be initialized to 0, including any fields added in the future.
It worked from the introduction of the ioctl until the new field was
added. How could anyone know about this requirement if it is not
documented? Some people might not even know that ioctl numbers encode
the size of the argument and therefore assume that the argument
structure is fixed. I think this is quite different from syscalls such
as clone3 which make the size argument explicit and where it can be
expected that the developer knows that the struct might grow when the
application is recompiled.
The new flag was added so that userspace can detect older kernels that
don't support the point field, such kernels return EINVAL when they
see the new flag.
Then why should the kernel not also use the absence of the flag to
detect older userspace that might be unaware of the point field?
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:11 ` Julian Orth
@ 2026-03-03 17:18 ` Michel Dänzer
2026-03-03 17:30 ` Julian Orth
2026-03-03 17:40 ` Maarten Lankhorst
0 siblings, 2 replies; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 17:18 UTC (permalink / raw)
To: Julian Orth
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On 3/3/26 18:11, Julian Orth wrote:
> On Tue, Mar 3, 2026 at 6:04 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>> On 3/3/26 17:54, Julian Orth wrote:
>>> On Tue, Mar 3, 2026 at 5:40 PM Maarten Lankhorst
>>> <maarten.lankhorst@linux.intel.com> wrote:
>>>>
>>>> There is precedence in the ioctl, the pad member is checked against zero for the same reason.
>>>
>>> I don't believe that this is comparable. Developers of code developed
>>> against an older kernel could look at the kernel and see that the pad
>>> field was checked against zero. They could not see the same for fields
>>> that didn't exist at the time.
>>
>> "Initialize only known fields" isn't a valid approach here. The full struct must be initialized to 0, including any fields added in the future.
>
> It worked from the introduction of the ioctl until the new field was
> added. How could anyone know about this requirement if it is not
> documented? Some people might not even know that ioctl numbers encode
> the size of the argument and therefore assume that the argument
> structure is fixed. I think this is quite different from syscalls such
> as clone3 which make the size argument explicit and where it can be
> expected that the developer knows that the struct might grow when the
> application is recompiled.
>
> The new flag was added so that userspace can detect older kernels that
> don't support the point field, such kernels return EINVAL when they
> see the new flag.
> Then why should the kernel not also use the absence of the flag to
> detect older userspace that might be unaware of the point field?
I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:18 ` Michel Dänzer
@ 2026-03-03 17:30 ` Julian Orth
2026-03-03 17:44 ` Maarten Lankhorst
2026-03-03 17:40 ` Maarten Lankhorst
1 sibling, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-03 17:30 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>
> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>
> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
At this point I think we're arguing about "how can ioctls be extended"
and "does userspace have to use memset" in general, not just about
this particular ioctl. You've made the argument that ioctls are not
extensible in general unless userspace uses memset. However, I'm not
yet convinced of this. As you've also said above, drm_ioctl happily
truncates or zero-extends ioctl arguments without returning an error
due to size mismatch. Therefore, the only way for userspace to detect
if the kernel supports the "extended" ioctl is to add a flag so that
the kernel can return an error if it doesn't know the flag. And then
that flag could also be used by the kernel to detect which fields of
the argument are potentially uninitialized.
That is why I asked above if you knew of any other examples where an
ioctl was extended and where memset(0) became effectively required due
to the extension.
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:18 ` Michel Dänzer
2026-03-03 17:30 ` Julian Orth
@ 2026-03-03 17:40 ` Maarten Lankhorst
2026-03-03 17:44 ` Julian Orth
1 sibling, 1 reply; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-03 17:40 UTC (permalink / raw)
To: Michel Dänzer, Julian Orth
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
Den 2026-03-03 kl. 18:18, skrev Michel Dänzer:
> On 3/3/26 18:11, Julian Orth wrote:
>> On Tue, Mar 3, 2026 at 6:04 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>> On 3/3/26 17:54, Julian Orth wrote:
>>>> On Tue, Mar 3, 2026 at 5:40 PM Maarten Lankhorst
>>>> <maarten.lankhorst@linux.intel.com> wrote:
>>>>>
>>>>> There is precedence in the ioctl, the pad member is checked against zero for the same reason.
>>>>
>>>> I don't believe that this is comparable. Developers of code developed
>>>> against an older kernel could look at the kernel and see that the pad
>>>> field was checked against zero. They could not see the same for fields
>>>> that didn't exist at the time.
>>>
>>> "Initialize only known fields" isn't a valid approach here. The full struct must be initialized to 0, including any fields added in the future.
>>
>> It worked from the introduction of the ioctl until the new field was
>> added. How could anyone know about this requirement if it is not
>> documented? Some people might not even know that ioctl numbers encode
>> the size of the argument and therefore assume that the argument
>> structure is fixed. I think this is quite different from syscalls such
>> as clone3 which make the size argument explicit and where it can be
>> expected that the developer knows that the struct might grow when the
>> application is recompiled.
>>
>> The new flag was added so that userspace can detect older kernels that
>> don't support the point field, such kernels return EINVAL when they
>> see the new flag.
>> Then why should the kernel not also use the absence of the flag to
>> detect older userspace that might be unaware of the point field?
>
> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>
>
> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
My point is that it works for old userspace without problems. It's only
newly compiled userspace with new headers that will run into problems.
The code as written would have continued to work, but if you update to
the new header and don't initialise the new members then it's a userspace
problem. It should not be worked around in the kernel, since it's newly
written bad userspace code, not old bad userspace code that stopped working
when the kernel changed.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:30 ` Julian Orth
@ 2026-03-03 17:44 ` Maarten Lankhorst
2026-03-03 18:53 ` Michel Dänzer
0 siblings, 1 reply; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-03 17:44 UTC (permalink / raw)
To: Julian Orth, Michel Dänzer
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
Hey,
Den 2026-03-03 kl. 18:30, skrev Julian Orth:
> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>
>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>>
>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
>
> At this point I think we're arguing about "how can ioctls be extended"
> and "does userspace have to use memset" in general, not just about
> this particular ioctl. You've made the argument that ioctls are not
> extensible in general unless userspace uses memset. However, I'm not
> yet convinced of this. As you've also said above, drm_ioctl happily
> truncates or zero-extends ioctl arguments without returning an error
> due to size mismatch. Therefore, the only way for userspace to detect
> if the kernel supports the "extended" ioctl is to add a flag so that
> the kernel can return an error if it doesn't know the flag. And then
> that flag could also be used by the kernel to detect which fields of
> the argument are potentially uninitialized.
>
> That is why I asked above if you knew of any other examples where an
> ioctl was extended and where memset(0) became effectively required due
> to the extension.
You don't even need to use memset, this would work too:
struct drm_syncobj_handle args = {
.flags = 0
};
Or simply struct drm_syncobj_handle args = { };
Kind regards,
~Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:40 ` Maarten Lankhorst
@ 2026-03-03 17:44 ` Julian Orth
2026-03-03 19:58 ` David Laight
0 siblings, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-03 17:44 UTC (permalink / raw)
To: Maarten Lankhorst
Cc: Michel Dänzer, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 6:41 PM Maarten Lankhorst
<maarten.lankhorst@linux.intel.com> wrote:
>
> My point is that it works for old userspace without problems. It's only
> newly compiled userspace with new headers that will run into problems.
> The code as written would have continued to work, but if you update to
> the new header and don't initialise the new members then it's a userspace
> problem. It should not be worked around in the kernel, since it's newly
> written bad userspace code, not old bad userspace code that stopped working
> when the kernel changed.
But it's not newly written. The example is, say, 5 year old code. The
binary that was compiled 5 years ago works fine as you say. But if you
take the same code and just run gcc again, the new binary will no
longer work.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:44 ` Maarten Lankhorst
@ 2026-03-03 18:53 ` Michel Dänzer
2026-03-03 19:12 ` Julian Orth
0 siblings, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-03 18:53 UTC (permalink / raw)
To: Maarten Lankhorst, Julian Orth
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
On 3/3/26 18:44, Maarten Lankhorst wrote:
> Den 2026-03-03 kl. 18:30, skrev Julian Orth:
>> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>
>>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>>>
>>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
>>
>> At this point I think we're arguing about "how can ioctls be extended"
>> and "does userspace have to use memset" in general, not just about
>> this particular ioctl. You've made the argument that ioctls are not
>> extensible in general unless userspace uses memset. However, I'm not
>> yet convinced of this. As you've also said above, drm_ioctl happily
>> truncates or zero-extends ioctl arguments without returning an error
>> due to size mismatch. Therefore, the only way for userspace to detect
>> if the kernel supports the "extended" ioctl is to add a flag so that
>> the kernel can return an error if it doesn't know the flag. And then
>> that flag could also be used by the kernel to detect which fields of
>> the argument are potentially uninitialized.
>>
>> That is why I asked above if you knew of any other examples where an
>> ioctl was extended and where memset(0) became effectively required due
>> to the extension.
Since it's always been effectively required for ioctl structs, "become" doesn't apply.
In terms of documentation, the "(How to avoid) Botching up ioctls" page says under Basics:
* Check all unused fields and flags and all the padding for whether it’s 0, and reject the ioctl if that’s not the case.
Which is what the code you're modifying here did: The code after the args->point checks doesn't use the point field, so it's checking that user space initialized the field to 0 per above.
This contradicts the arguments in the commit log, so I'm leaning toward objecting to this patch now.
> You don't even need to use memset, this would work too:
>
> struct drm_syncobj_handle args = {
> .flags = 0
> };
TL;DR: This method isn't 100% safe either.
It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
FWIW, libdrm uses memset for all ioctl structs.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 18:53 ` Michel Dänzer
@ 2026-03-03 19:12 ` Julian Orth
2026-03-04 9:57 ` Maarten Lankhorst
2026-03-04 11:15 ` Michel Dänzer
0 siblings, 2 replies; 36+ messages in thread
From: Julian Orth @ 2026-03-03 19:12 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>
> On 3/3/26 18:44, Maarten Lankhorst wrote:
> > Den 2026-03-03 kl. 18:30, skrev Julian Orth:
> >> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> >>>
> >>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
> >>>
> >>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
> >>
> >> At this point I think we're arguing about "how can ioctls be extended"
> >> and "does userspace have to use memset" in general, not just about
> >> this particular ioctl. You've made the argument that ioctls are not
> >> extensible in general unless userspace uses memset. However, I'm not
> >> yet convinced of this. As you've also said above, drm_ioctl happily
> >> truncates or zero-extends ioctl arguments without returning an error
> >> due to size mismatch. Therefore, the only way for userspace to detect
> >> if the kernel supports the "extended" ioctl is to add a flag so that
> >> the kernel can return an error if it doesn't know the flag. And then
> >> that flag could also be used by the kernel to detect which fields of
> >> the argument are potentially uninitialized.
> >>
> >> That is why I asked above if you knew of any other examples where an
> >> ioctl was extended and where memset(0) became effectively required due
> >> to the extension.
>
> Since it's always been effectively required for ioctl structs, "become" doesn't apply.
>
>
> In terms of documentation, the "(How to avoid) Botching up ioctls" page says under Basics:
>
> * Check all unused fields and flags and all the padding for whether it’s 0, and reject the ioctl if that’s not the case.
>
> Which is what the code you're modifying here did: The code after the args->point checks doesn't use the point field, so it's checking that user space initialized the field to 0 per above.
I don't believe that is true. The old code only checked args->point if
the flags argument was 0. If the flags argument contained
EXPORT_SYNC_FILE but not TIMELINE, then the old code ignored
args->point completely. The patch suggested by Maarten does what
you're suggesting: It unconditionally verifies that args->point does
not contain garbage. However, since the original code only used
args->points if TIMELINE was set, I believe the intention behind the
TIMELINE flag was to ignore the args->point field if the flag was
unset. That assumption is the basis for my patch.
>
> This contradicts the arguments in the commit log, so I'm leaning toward objecting to this patch now.
>
>
> > You don't even need to use memset, this would work too:
> >
> > struct drm_syncobj_handle args = {
> > .flags = 0
> > };
>
> TL;DR: This method isn't 100% safe either.
>
> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
I don't think this is workable. There is a lot of code out there that
effectively vendors the ioctl definitions (and so is not affected by
new fields) and relies on field-based initialization affecting all
significant bytes. For example
https://github.com/Smithay/drm-rs/blob/08dee22f0dcfa4a73a18ca3a954d4f7c2c749c03/drm-ffi/src/syncobj.rs#L48-L58.
>
> FWIW, libdrm uses memset for all ioctl structs.
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 17:44 ` Julian Orth
@ 2026-03-03 19:58 ` David Laight
2026-03-04 10:35 ` Maarten Lankhorst
0 siblings, 1 reply; 36+ messages in thread
From: David Laight @ 2026-03-03 19:58 UTC (permalink / raw)
To: Julian Orth
Cc: Maarten Lankhorst, Michel Dänzer, Christian König,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Dmitry Osipenko, Rob Clark, dri-devel, linux-kernel
On Tue, 3 Mar 2026 18:44:59 +0100
Julian Orth <ju.orth@gmail.com> wrote:
> On Tue, Mar 3, 2026 at 6:41 PM Maarten Lankhorst
> <maarten.lankhorst@linux.intel.com> wrote:
> >
> > My point is that it works for old userspace without problems. It's only
> > newly compiled userspace with new headers that will run into problems.
> > The code as written would have continued to work, but if you update to
> > the new header and don't initialise the new members then it's a userspace
> > problem. It should not be worked around in the kernel, since it's newly
> > written bad userspace code, not old bad userspace code that stopped working
> > when the kernel changed.
>
> But it's not newly written. The example is, say, 5 year old code. The
> binary that was compiled 5 years ago works fine as you say. But if you
> take the same code and just run gcc again, the new binary will no
> longer work.
>
Worse, the recompiled version may well work when you test it, and even
when deployed.
But you'll get non-obvious random failures - a support nightmare.
Probably best code is something like:
case OLD_IOCTL_CODE:
if (ioc->flag & NEW_FLAG)
return -EINVAL;
/* FALLTHROUGH *.
case NEW_IOCTL_CODE:
if (!(ioc->flag & NEW_FLAG))
ioc->new_field = 0;
David
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 19:12 ` Julian Orth
@ 2026-03-04 9:57 ` Maarten Lankhorst
2026-03-04 11:15 ` Michel Dänzer
1 sibling, 0 replies; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-04 9:57 UTC (permalink / raw)
To: Julian Orth, Michel Dänzer
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
Hey,
Den 2026-03-03 kl. 20:12, skrev Julian Orth:
> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>
>> On 3/3/26 18:44, Maarten Lankhorst wrote:
>>> Den 2026-03-03 kl. 18:30, skrev Julian Orth:
>>>> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>>>
>>>>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>>>>>
>>>>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
>>>>
>>>> At this point I think we're arguing about "how can ioctls be extended"
>>>> and "does userspace have to use memset" in general, not just about
>>>> this particular ioctl. You've made the argument that ioctls are not
>>>> extensible in general unless userspace uses memset. However, I'm not
>>>> yet convinced of this. As you've also said above, drm_ioctl happily
>>>> truncates or zero-extends ioctl arguments without returning an error
>>>> due to size mismatch. Therefore, the only way for userspace to detect
>>>> if the kernel supports the "extended" ioctl is to add a flag so that
>>>> the kernel can return an error if it doesn't know the flag. And then
>>>> that flag could also be used by the kernel to detect which fields of
>>>> the argument are potentially uninitialized.
>>>>
>>>> That is why I asked above if you knew of any other examples where an
>>>> ioctl was extended and where memset(0) became effectively required due
>>>> to the extension.
>>
>> Since it's always been effectively required for ioctl structs, "become" doesn't apply.
>>
>>
>> In terms of documentation, the "(How to avoid) Botching up ioctls" page says under Basics:
>>
>> * Check all unused fields and flags and all the padding for whether it’s 0, and reject the ioctl if that’s not the case.
>>
>> Which is what the code you're modifying here did: The code after the args->point checks doesn't use the point field, so it's checking that user space initialized the field to 0 per above.
>
> I don't believe that is true. The old code only checked args->point if
> the flags argument was 0. If the flags argument contained
> EXPORT_SYNC_FILE but not TIMELINE, then the old code ignored
> args->point completely. The patch suggested by Maarten does what
> you're suggesting: It unconditionally verifies that args->point does
> not contain garbage. However, since the original code only used
> args->points if TIMELINE was set, I believe the intention behind the
> TIMELINE flag was to ignore the args->point field if the flag was
> unset. That assumption is the basis for my patch.
>
>>
>> This contradicts the arguments in the commit log, so I'm leaning toward objecting to this patch now.
>>
>>
>>> You don't even need to use memset, this would work too:
>>>
>>> struct drm_syncobj_handle args = {
>>> .flags = 0
>>> };
>>
>> TL;DR: This method isn't 100% safe either.
>>
>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
>
> I don't think this is workable. There is a lot of code out there that
> effectively vendors the ioctl definitions (and so is not affected by
> new fields) and relies on field-based initialization affecting all
> significant bytes. For example
> https://github.com/Smithay/drm-rs/blob/08dee22f0dcfa4a73a18ca3a954d4f7c2c749c03/drm-ffi/src/syncobj.rs#L48-L58.
Vendoring is not affected. When you carry your own definition, it's your
responsibility for updating the users if you update the struct too.
Using rust here is a good example. The rust code would still use the old definition.
If you use it against the new definition it fails to compile, or use default valuesif asked.
You would notice your newly introduced bug at compile time.
Kind regards,
~Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 19:58 ` David Laight
@ 2026-03-04 10:35 ` Maarten Lankhorst
0 siblings, 0 replies; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-04 10:35 UTC (permalink / raw)
To: David Laight, Julian Orth
Cc: Michel Dänzer, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
Hey,
Den 2026-03-03 kl. 20:58, skrev David Laight:
> On Tue, 3 Mar 2026 18:44:59 +0100
> Julian Orth <ju.orth@gmail.com> wrote:
>
>> On Tue, Mar 3, 2026 at 6:41 PM Maarten Lankhorst
>> <maarten.lankhorst@linux.intel.com> wrote:
>>>
>>> My point is that it works for old userspace without problems. It's only
>>> newly compiled userspace with new headers that will run into problems.
>>> The code as written would have continued to work, but if you update to
>>> the new header and don't initialise the new members then it's a userspace
>>> problem. It should not be worked around in the kernel, since it's newly
>>> written bad userspace code, not old bad userspace code that stopped working
>>> when the kernel changed.
>>
>> But it's not newly written. The example is, say, 5 year old code. The
>> binary that was compiled 5 years ago works fine as you say. But if you
>> take the same code and just run gcc again, the new binary will no
>> longer work.
>>
>
> Worse, the recompiled version may well work when you test it, and even
> when deployed.
> But you'll get non-obvious random failures - a support nightmare.
I believe in a lot of cases the headers are simply copied to the project,
so it will continue to work.
I don't see a difference between moving to a new compiler. Compiling code
from 5 years ago might also run into new compiler warnings that didn't
exist on the older version of the compiler.
> Probably best code is something like:
> case OLD_IOCTL_CODE:
> if (ioc->flag & NEW_FLAG)
> return -EINVAL;
> /* FALLTHROUGH *.
> case NEW_IOCTL_CODE:
> if (!(ioc->flag & NEW_FLAG))
> ioc->new_field = 0;
>
> David
Yeah, that is what we do by explicitly checking the size parameter. Any
undefined members are zero'd. If you define the new member in userspace,
you're also taking on the responsibility for having it contained defined
information, even if you only zero the struct.
Kind regards,
~Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-03 19:12 ` Julian Orth
2026-03-04 9:57 ` Maarten Lankhorst
@ 2026-03-04 11:15 ` Michel Dänzer
2026-03-04 11:25 ` Julian Orth
1 sibling, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-04 11:15 UTC (permalink / raw)
To: Julian Orth
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On 3/3/26 20:12, Julian Orth wrote:
> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>
>> On 3/3/26 18:44, Maarten Lankhorst wrote:
>>> Den 2026-03-03 kl. 18:30, skrev Julian Orth:
>>>> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>>>
>>>>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>>>>>
>>>>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
>>>>
>>>> At this point I think we're arguing about "how can ioctls be extended"
>>>> and "does userspace have to use memset" in general, not just about
>>>> this particular ioctl. You've made the argument that ioctls are not
>>>> extensible in general unless userspace uses memset. However, I'm not
>>>> yet convinced of this. As you've also said above, drm_ioctl happily
>>>> truncates or zero-extends ioctl arguments without returning an error
>>>> due to size mismatch. Therefore, the only way for userspace to detect
>>>> if the kernel supports the "extended" ioctl is to add a flag so that
>>>> the kernel can return an error if it doesn't know the flag. And then
>>>> that flag could also be used by the kernel to detect which fields of
>>>> the argument are potentially uninitialized.
>>>>
>>>> That is why I asked above if you knew of any other examples where an
>>>> ioctl was extended and where memset(0) became effectively required due
>>>> to the extension.
>>
>> Since it's always been effectively required for ioctl structs, "become" doesn't apply.
>>
>>
>> In terms of documentation, the "(How to avoid) Botching up ioctls" page says under Basics:
>>
>> * Check all unused fields and flags and all the padding for whether it’s 0, and reject the ioctl if that’s not the case.
>>
>> Which is what the code you're modifying here did: The code after the args->point checks doesn't use the point field, so it's checking that user space initialized the field to 0 per above.
>
> I don't believe that is true. The old code only checked args->point if
> the flags argument was 0. If the flags argument contained
> EXPORT_SYNC_FILE but not TIMELINE, then the old code ignored
> args->point completely.
Right, the code didn't fully implement the rule which has been documented for 13 years. Makes no practical difference though, the user-space code would have hit a failure regardless.
> However, since the original code only used args->points if TIMELINE was set,
> I believe the intention behind the TIMELINE flag was to ignore the args->point
> field if the flag was unset. That assumption is the basis for my patch.
Whatever Rob's intention was, checking the value of the local variable instead seems of little use, since it can have a non-0 value only if the TIMELINE flag is set. If the intention is to catch the TIMELINE flag being set without the IMPORT_SYNC_FILE flag, that should be done directly instead, or it won't be caught if args->point is 0.
>>> You don't even need to use memset, this would work too:
>>>
>>> struct drm_syncobj_handle args = {
>>> .flags = 0
>>> };
>>
>> TL;DR: This method isn't 100% safe either.
>>
>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
>
> I don't think this is workable.
libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-04 11:15 ` Michel Dänzer
@ 2026-03-04 11:25 ` Julian Orth
2026-03-04 11:47 ` Michel Dänzer
2026-03-05 9:47 ` Maarten Lankhorst
0 siblings, 2 replies; 36+ messages in thread
From: Julian Orth @ 2026-03-04 11:25 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Wed, Mar 4, 2026 at 12:15 PM Michel Dänzer
<michel.daenzer@mailbox.org> wrote:
>
> On 3/3/26 20:12, Julian Orth wrote:
> > On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> >>
> >> On 3/3/26 18:44, Maarten Lankhorst wrote:
> >>> Den 2026-03-03 kl. 18:30, skrev Julian Orth:
> >>>> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> >>>>>
> >>>>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
> >>>>>
> >>>>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
> >>>>
> >>>> At this point I think we're arguing about "how can ioctls be extended"
> >>>> and "does userspace have to use memset" in general, not just about
> >>>> this particular ioctl. You've made the argument that ioctls are not
> >>>> extensible in general unless userspace uses memset. However, I'm not
> >>>> yet convinced of this. As you've also said above, drm_ioctl happily
> >>>> truncates or zero-extends ioctl arguments without returning an error
> >>>> due to size mismatch. Therefore, the only way for userspace to detect
> >>>> if the kernel supports the "extended" ioctl is to add a flag so that
> >>>> the kernel can return an error if it doesn't know the flag. And then
> >>>> that flag could also be used by the kernel to detect which fields of
> >>>> the argument are potentially uninitialized.
> >>>>
> >>>> That is why I asked above if you knew of any other examples where an
> >>>> ioctl was extended and where memset(0) became effectively required due
> >>>> to the extension.
> >>
> >> Since it's always been effectively required for ioctl structs, "become" doesn't apply.
> >>
> >>
> >> In terms of documentation, the "(How to avoid) Botching up ioctls" page says under Basics:
> >>
> >> * Check all unused fields and flags and all the padding for whether it’s 0, and reject the ioctl if that’s not the case.
> >>
> >> Which is what the code you're modifying here did: The code after the args->point checks doesn't use the point field, so it's checking that user space initialized the field to 0 per above.
> >
> > I don't believe that is true. The old code only checked args->point if
> > the flags argument was 0. If the flags argument contained
> > EXPORT_SYNC_FILE but not TIMELINE, then the old code ignored
> > args->point completely.
>
> Right, the code didn't fully implement the rule which has been documented for 13 years. Makes no practical difference though, the user-space code would have hit a failure regardless.
>
>
> > However, since the original code only used args->points if TIMELINE was set,
> > I believe the intention behind the TIMELINE flag was to ignore the args->point
> > field if the flag was unset. That assumption is the basis for my patch.
>
> Whatever Rob's intention was, checking the value of the local variable instead seems of little use, since it can have a non-0 value only if the TIMELINE flag is set. If the intention is to catch the TIMELINE flag being set without the IMPORT_SYNC_FILE flag, that should be done directly instead, or it won't be caught if args->point is 0.
You're right, the better check would probably have been (using a shorthand)
if (!IMPORT_SYNC_FILE && TIMELINE) return EINVAL;
However, since that was not done at the time, there might now be
userspace that relies on this not returning an error as long as the
point is 0. The intention of my patch was to be strictly more lenient.
>
>
> >>> You don't even need to use memset, this would work too:
> >>>
> >>> struct drm_syncobj_handle args = {
> >>> .flags = 0
> >>> };
> >>
> >> TL;DR: This method isn't 100% safe either.
> >>
> >> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
> >
> > I don't think this is workable.
>
> libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
Using memset to initialize padding bytes between fields is workable.
Having the kernel add checks for this for existing ioctls is not
workable because it would break usespace that doesn't do this. Which
is every rust program out there as far as I can tell.
I'm not aware of any ioctls that actually have padding bytes between
fields so this discussion is mostly academic.
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-04 11:25 ` Julian Orth
@ 2026-03-04 11:47 ` Michel Dänzer
2026-03-04 12:32 ` Julian Orth
2026-03-05 9:47 ` Maarten Lankhorst
1 sibling, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-04 11:47 UTC (permalink / raw)
To: Julian Orth
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On 3/4/26 12:25, Julian Orth wrote:
> On Wed, Mar 4, 2026 at 12:15 PM Michel Dänzer
> <michel.daenzer@mailbox.org> wrote:
>> On 3/3/26 20:12, Julian Orth wrote:
>>> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>> On 3/3/26 18:44, Maarten Lankhorst wrote:
>>>>>
>>>>> You don't even need to use memset, this would work too:
>>>>>
>>>>> struct drm_syncobj_handle args = {
>>>>> .flags = 0
>>>>> };
>>>>
>>>> TL;DR: This method isn't 100% safe either.
>>>>
>>>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
>>>
>>> I don't think this is workable.
>>
>> libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
>
> Using memset to initialize padding bytes between fields is workable.
> Having the kernel add checks for this for existing ioctls is not
> workable because it would break usespace that doesn't do this.
As discussed in this thread, memset is also required for when the size of an ioctl struct is extended, even if there is no such padding.
> Which is every rust program out there as far as I can tell.
That's surprising. Surely there must be some unsafe code involved which allows uninitialized memory to be passed to ioctl()?
> I'm not aware of any ioctls that actually have padding bytes between
> fields so this discussion is mostly academic.
I covered that in my previous post quoted above.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-04 11:47 ` Michel Dänzer
@ 2026-03-04 12:32 ` Julian Orth
2026-03-04 14:29 ` Michel Dänzer
0 siblings, 1 reply; 36+ messages in thread
From: Julian Orth @ 2026-03-04 12:32 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Wed, Mar 4, 2026 at 12:47 PM Michel Dänzer
<michel.daenzer@mailbox.org> wrote:
>
> On 3/4/26 12:25, Julian Orth wrote:
> > On Wed, Mar 4, 2026 at 12:15 PM Michel Dänzer
> > <michel.daenzer@mailbox.org> wrote:
> >> On 3/3/26 20:12, Julian Orth wrote:
> >>> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> >>>> On 3/3/26 18:44, Maarten Lankhorst wrote:
> >>>>>
> >>>>> You don't even need to use memset, this would work too:
> >>>>>
> >>>>> struct drm_syncobj_handle args = {
> >>>>> .flags = 0
> >>>>> };
> >>>>
> >>>> TL;DR: This method isn't 100% safe either.
> >>>>
> >>>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
> >>>
> >>> I don't think this is workable.
> >>
> >> libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
> >
> > Using memset to initialize padding bytes between fields is workable.
> > Having the kernel add checks for this for existing ioctls is not
> > workable because it would break usespace that doesn't do this.
>
> As discussed in this thread, memset is also required for when the size of an ioctl struct is extended, even if there is no such padding.
That is not a concern in rust code. If the rust code extends the
definition of the struct, all call sites will cause a compilation
error until the new field is also initialized.
The issue I'm talking about here is strictly about padding bytes between fields.
>
>
> > Which is every rust program out there as far as I can tell.
>
> That's surprising. Surely there must be some unsafe code involved which allows uninitialized memory to be passed to ioctl()?
The memory is not uninitialized from the perspective of the rust
language since all fields are initialized. Only the padding bytes are
uninitialized and they cannot be accessed in safe rust, therefore no
unsafe is required.
I've never seen any rust code that uses memset to initialize ioctl
arguments. It assumes that the ioctl implementation will only read
from the named fields. Therefore, while the ioctl syscall itself is
unsafe, developers assume that the safety requirements are satisfied
in this regard.
>
>
> > I'm not aware of any ioctls that actually have padding bytes between
> > fields so this discussion is mostly academic.
>
> I covered that in my previous post quoted above.
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-04 12:32 ` Julian Orth
@ 2026-03-04 14:29 ` Michel Dänzer
2026-03-04 14:35 ` Julian Orth
0 siblings, 1 reply; 36+ messages in thread
From: Michel Dänzer @ 2026-03-04 14:29 UTC (permalink / raw)
To: Julian Orth
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On 3/4/26 13:32, Julian Orth wrote:
> On Wed, Mar 4, 2026 at 12:47 PM Michel Dänzer
> <michel.daenzer@mailbox.org> wrote:
>> On 3/4/26 12:25, Julian Orth wrote:
>>> On Wed, Mar 4, 2026 at 12:15 PM Michel Dänzer
>>> <michel.daenzer@mailbox.org> wrote:
>>>> On 3/3/26 20:12, Julian Orth wrote:
>>>>> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>>>> On 3/3/26 18:44, Maarten Lankhorst wrote:
>>>>>>>
>>>>>>> You don't even need to use memset, this would work too:
>>>>>>>
>>>>>>> struct drm_syncobj_handle args = {
>>>>>>> .flags = 0
>>>>>>> };
>>>>>>
>>>>>> TL;DR: This method isn't 100% safe either.
>>>>>>
>>>>>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
>>>>>
>>>>> I don't think this is workable.
>>>>
>>>> libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
>>>
>>> Using memset to initialize padding bytes between fields is workable.
>>> Having the kernel add checks for this for existing ioctls is not
>>> workable because it would break usespace that doesn't do this.
>>
>> As discussed in this thread, memset is also required for when the size of an ioctl struct is extended, even if there is no such padding.
>
> That is not a concern in rust code. If the rust code extends the
> definition of the struct, all call sites will cause a compilation
> error until the new field is also initialized.
>
> The issue I'm talking about here is strictly about padding bytes between fields.
So this is not related to the issue which motivated your patch?
>>> Which is every rust program out there as far as I can tell.
>>
>> That's surprising. Surely there must be some unsafe code involved which allows uninitialized memory to be passed to ioctl()?
>
> The memory is not uninitialized from the perspective of the rust
> language since all fields are initialized. Only the padding bytes are
> uninitialized and they cannot be accessed in safe rust, therefore no
> unsafe is required.
>
> I've never seen any rust code that uses memset to initialize ioctl
> arguments. It assumes that the ioctl implementation will only read
> from the named fields. Therefore, while the ioctl syscall itself is
> unsafe, developers assume that the safety requirements are satisfied
> in this regard.
As discussed in this thread, that's not a valid assumption and may blow up in their face sooner or later. ("No padding not covered by any fields" is best-effort, not a guarantee)
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-04 14:29 ` Michel Dänzer
@ 2026-03-04 14:35 ` Julian Orth
0 siblings, 0 replies; 36+ messages in thread
From: Julian Orth @ 2026-03-04 14:35 UTC (permalink / raw)
To: Michel Dänzer
Cc: Maarten Lankhorst, Christian König, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Dmitry Osipenko,
Rob Clark, dri-devel, linux-kernel
On Wed, Mar 4, 2026 at 3:30 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>
> On 3/4/26 13:32, Julian Orth wrote:
> > On Wed, Mar 4, 2026 at 12:47 PM Michel Dänzer
> > <michel.daenzer@mailbox.org> wrote:
> >> On 3/4/26 12:25, Julian Orth wrote:
> >>> On Wed, Mar 4, 2026 at 12:15 PM Michel Dänzer
> >>> <michel.daenzer@mailbox.org> wrote:
> >>>> On 3/3/26 20:12, Julian Orth wrote:
> >>>>> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> >>>>>> On 3/3/26 18:44, Maarten Lankhorst wrote:
> >>>>>>>
> >>>>>>> You don't even need to use memset, this would work too:
> >>>>>>>
> >>>>>>> struct drm_syncobj_handle args = {
> >>>>>>> .flags = 0
> >>>>>>> };
> >>>>>>
> >>>>>> TL;DR: This method isn't 100% safe either.
> >>>>>>
> >>>>>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
> >>>>>
> >>>>> I don't think this is workable.
> >>>>
> >>>> libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
> >>>
> >>> Using memset to initialize padding bytes between fields is workable.
> >>> Having the kernel add checks for this for existing ioctls is not
> >>> workable because it would break usespace that doesn't do this.
> >>
> >> As discussed in this thread, memset is also required for when the size of an ioctl struct is extended, even if there is no such padding.
> >
> > That is not a concern in rust code. If the rust code extends the
> > definition of the struct, all call sites will cause a compilation
> > error until the new field is also initialized.
> >
> > The issue I'm talking about here is strictly about padding bytes between fields.
>
> So this is not related to the issue which motivated your patch?
I don't believe the ioctls in question contain padding bytes on any
architecture. This thread is in response to your statement above:
>>>>>>> struct drm_syncobj_handle args = {
>>>>>>> .flags = 0
>>>>>>> };
>>>>>>
>>>>>> TL;DR: This method isn't 100% safe either.
>>>>>>
>>>>>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
----
>
>
> >>> Which is every rust program out there as far as I can tell.
> >>
> >> That's surprising. Surely there must be some unsafe code involved which allows uninitialized memory to be passed to ioctl()?
> >
> > The memory is not uninitialized from the perspective of the rust
> > language since all fields are initialized. Only the padding bytes are
> > uninitialized and they cannot be accessed in safe rust, therefore no
> > unsafe is required.
> >
> > I've never seen any rust code that uses memset to initialize ioctl
> > arguments. It assumes that the ioctl implementation will only read
> > from the named fields. Therefore, while the ioctl syscall itself is
> > unsafe, developers assume that the safety requirements are satisfied
> > in this regard.
>
> As discussed in this thread, that's not a valid assumption and may blow up in their face sooner or later. ("No padding not covered by any fields" is best-effort, not a guarantee)
>
>
> --
> Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
> https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
2026-03-04 11:25 ` Julian Orth
2026-03-04 11:47 ` Michel Dänzer
@ 2026-03-05 9:47 ` Maarten Lankhorst
1 sibling, 0 replies; 36+ messages in thread
From: Maarten Lankhorst @ 2026-03-05 9:47 UTC (permalink / raw)
To: Julian Orth, Michel Dänzer
Cc: Christian König, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Dmitry Osipenko, Rob Clark,
dri-devel, linux-kernel
Hey,
Den 2026-03-04 kl. 12:25, skrev Julian Orth:
> On Wed, Mar 4, 2026 at 12:15 PM Michel Dänzer
> <michel.daenzer@mailbox.org> wrote:
>>
>> On 3/3/26 20:12, Julian Orth wrote:
>>> On Tue, Mar 3, 2026 at 7:53 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>>
>>>> On 3/3/26 18:44, Maarten Lankhorst wrote:
>>>>> Den 2026-03-03 kl. 18:30, skrev Julian Orth:
>>>>>> On Tue, Mar 3, 2026 at 6:18 PM Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>>>>>>>
>>>>>>> I wrote in my first post in this thread that I don't object to your patch, so you can relax and stop trying to convince me not to object to it. :)
>>>>>>>
>>>>>>> I'm just pointing out that this is working around broken user-space code, and that there are other similar cases where that kind of broken users-space code couldn't be worked around in the kernel, so it's better to also fix the user-space code anyway.
>>>>>>
>>>>>> At this point I think we're arguing about "how can ioctls be extended"
>>>>>> and "does userspace have to use memset" in general, not just about
>>>>>> this particular ioctl. You've made the argument that ioctls are not
>>>>>> extensible in general unless userspace uses memset. However, I'm not
>>>>>> yet convinced of this. As you've also said above, drm_ioctl happily
>>>>>> truncates or zero-extends ioctl arguments without returning an error
>>>>>> due to size mismatch. Therefore, the only way for userspace to detect
>>>>>> if the kernel supports the "extended" ioctl is to add a flag so that
>>>>>> the kernel can return an error if it doesn't know the flag. And then
>>>>>> that flag could also be used by the kernel to detect which fields of
>>>>>> the argument are potentially uninitialized.
>>>>>>
>>>>>> That is why I asked above if you knew of any other examples where an
>>>>>> ioctl was extended and where memset(0) became effectively required due
>>>>>> to the extension.
>>>>
>>>> Since it's always been effectively required for ioctl structs, "become" doesn't apply.
>>>>
>>>>
>>>> In terms of documentation, the "(How to avoid) Botching up ioctls" page says under Basics:
>>>>
>>>> * Check all unused fields and flags and all the padding for whether it’s 0, and reject the ioctl if that’s not the case.
>>>>
>>>> Which is what the code you're modifying here did: The code after the args->point checks doesn't use the point field, so it's checking that user space initialized the field to 0 per above.
>>>
>>> I don't believe that is true. The old code only checked args->point if
>>> the flags argument was 0. If the flags argument contained
>>> EXPORT_SYNC_FILE but not TIMELINE, then the old code ignored
>>> args->point completely.
>>
>> Right, the code didn't fully implement the rule which has been documented for 13 years. Makes no practical difference though, the user-space code would have hit a failure regardless.
>>
>>
>>> However, since the original code only used args->points if TIMELINE was set,
>>> I believe the intention behind the TIMELINE flag was to ignore the args->point
>>> field if the flag was unset. That assumption is the basis for my patch.
>>
>> Whatever Rob's intention was, checking the value of the local variable instead seems of little use, since it can have a non-0 value only if the TIMELINE flag is set. If the intention is to catch the TIMELINE flag being set without the IMPORT_SYNC_FILE flag, that should be done directly instead, or it won't be caught if args->point is 0.
>
> You're right, the better check would probably have been (using a shorthand)
>
> if (!IMPORT_SYNC_FILE && TIMELINE) return EINVAL;
>
> However, since that was not done at the time, there might now be
> userspace that relies on this not returning an error as long as the
> point is 0. The intention of my patch was to be strictly more lenient.
>
>>
>>
>>>>> You don't even need to use memset, this would work too:
>>>>>
>>>>> struct drm_syncobj_handle args = {
>>>>> .flags = 0
>>>>> };
>>>>
>>>> TL;DR: This method isn't 100% safe either.
>>>>
>>>> It won't initialize any padding which isn't covered by any struct field. We try to avoid that and have explicit padding fields instead, mistakes may happen though, and in theory such padding could later be used for a new field.
>>>
>>> I don't think this is workable.
>>
>> libdrm begs to differ. It shows that it's not only workable but really easy. There's no reason for doing it any other way.
>
> Using memset to initialize padding bytes between fields is workable.
> Having the kernel add checks for this for existing ioctls is not
> workable because it would break usespace that doesn't do this. Which
> is every rust program out there as far as I can tell.
>
> I'm not aware of any ioctls that actually have padding bytes between
> fields so this discussion is mostly academic.
This is exactly why we attempt to ensure there is no implicit padding,
and explicitly check for all 'pad' members to be zero. Additionally
we attempt to stay 32-bits vs 64-bits clean, so no handling needs to
be performed in the compat ioctl's layout.
Kind regards,
~Maarten Lankhorst
^ permalink raw reply [flat|nested] 36+ messages in thread
end of thread, other threads:[~2026-03-05 9:47 UTC | newest]
Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-01 12:34 [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack Julian Orth
2026-03-02 11:27 ` Christian König
2026-03-02 11:54 ` Dmitry Osipenko
2026-03-03 11:17 ` Michel Dänzer
2026-03-03 11:23 ` Julian Orth
2026-03-03 11:38 ` Michel Dänzer
2026-03-03 11:41 ` Julian Orth
2026-03-03 14:53 ` Maarten Lankhorst
2026-03-03 14:59 ` Christian König
2026-03-03 15:15 ` Maarten Lankhorst
2026-03-03 15:21 ` Julian Orth
2026-03-03 17:02 ` Michel Dänzer
2026-03-03 15:29 ` Michel Dänzer
2026-03-03 15:36 ` Julian Orth
2026-03-03 16:40 ` Maarten Lankhorst
2026-03-03 16:54 ` Julian Orth
2026-03-03 17:04 ` Michel Dänzer
2026-03-03 17:11 ` Julian Orth
2026-03-03 17:18 ` Michel Dänzer
2026-03-03 17:30 ` Julian Orth
2026-03-03 17:44 ` Maarten Lankhorst
2026-03-03 18:53 ` Michel Dänzer
2026-03-03 19:12 ` Julian Orth
2026-03-04 9:57 ` Maarten Lankhorst
2026-03-04 11:15 ` Michel Dänzer
2026-03-04 11:25 ` Julian Orth
2026-03-04 11:47 ` Michel Dänzer
2026-03-04 12:32 ` Julian Orth
2026-03-04 14:29 ` Michel Dänzer
2026-03-04 14:35 ` Julian Orth
2026-03-05 9:47 ` Maarten Lankhorst
2026-03-03 17:40 ` Maarten Lankhorst
2026-03-03 17:44 ` Julian Orth
2026-03-03 19:58 ` David Laight
2026-03-04 10:35 ` Maarten Lankhorst
2026-03-03 17:05 ` Maarten Lankhorst
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox