[PATCH] drm/etnaviv: reject read-only userptr BOs as perfmon targets

Junghyun Park posted 1 patch 1 week ago
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 7 +++++++
1 file changed, 7 insertions(+)
[PATCH] drm/etnaviv: reject read-only userptr BOs as perfmon targets
Posted by Junghyun Park 1 week ago
submit_perfmon_validate() lets a submission name any buffer object (BO)
as the target for perfmon results, but the kernel writes those results
back into the BO on job completion: "*pmr->bo_vma = pmr->sequence" in
sync_point_perfmon_sample_post() and the counter store in
etnaviv_perfmon_process(). It never checks that the BO was submitted
writable.

An unprivileged user can register a read-only userptr BO backed by the
page-cache page of a file it can only read, via
DRM_IOCTL_ETNAVIV_GEM_USERPTR (userptr.ro = true, pinned without
FOLL_WRITE), then name it as a perfmon target in
DRM_IOCTL_ETNAVIV_GEM_SUBMIT. etnaviv_gem_vmap_impl() maps the CACHED
BO PAGE_KERNEL (writable) regardless of userptr.ro, so pmr->bo_vma
becomes a writable kernel alias of the read-only page. On completion
the kernel stores a caller-controlled 32-bit value into it, overwriting
the in-memory page-cache contents of a file the caller can only read.
All etnaviv ioctls are DRM_RENDER_ALLOW, so no elevated privilege is
required.

Reject a read-only userptr BO named as a perfmon result target. The
submit-time BO_WRITE flag is not usable for this: it is caller-supplied
and describes GPU access, so it neither reflects nor constrains how the
userptr pages were pinned.

Fixes: 249300c740e5 ("drm/etnaviv: add performance monitor request processing")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5
Signed-off-by: Junghyun Park <mastpark2001@snu.ac.kr>
---
 drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 1a77a09b3..e44fa40fd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -322,6 +322,13 @@ static int submit_perfmon_validate(struct etnaviv_gem_submit *submit,
 		if (ret)
 			return ret;

+		/* perfmon writes the result back; refuse a read-only userptr */
+		if (bo->obj->userptr.ro) {
+			DRM_ERROR("perfmon request: BO %u is a read-only userptr\n",
+				  r->read_idx);
+			return -EINVAL;
+		}
+
 		/* at offset 0 a sequence number gets stored used for userspace sync */
 		if (r->read_offset == 0) {
 			DRM_ERROR("perfmon request: offset is 0");