public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: "Julian Orth" <ju.orth@gmail.com>,
	"Michel Dänzer" <michel.daenzer@mailbox.org>
Cc: "Christian König" <christian.koenig@amd.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Dmitry Osipenko" <dmitry.osipenko@collabora.com>,
	"Rob Clark" <robin.clark@oss.qualcomm.com>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] drm/syncobj: Fix handle <-> fd ioctls with dirty stack
Date: Tue, 3 Mar 2026 17:40:43 +0100	[thread overview]
Message-ID: <bc3417d9-d191-4cc7-95e0-968b0b9bec05@linux.intel.com> (raw)
In-Reply-To: <CAHijbEXkn3+E_u1+aZgLT+pQ_vLYvKKv9VU_5kOuEaFheLRQeg@mail.gmail.com>

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);


  reply	other threads:[~2026-03-03 16:40 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bc3417d9-d191-4cc7-95e0-968b0b9bec05@linux.intel.com \
    --to=maarten.lankhorst@linux.intel.com \
    --cc=airlied@gmail.com \
    --cc=christian.koenig@amd.com \
    --cc=dmitry.osipenko@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=ju.orth@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michel.daenzer@mailbox.org \
    --cc=mripard@kernel.org \
    --cc=robin.clark@oss.qualcomm.com \
    --cc=simona@ffwll.ch \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox