Mali: valhall: from ARM: Fix UAF issue of user IO pages after group fatal error

The user IO page mappings were not unmapped properly when a group is
terminated, which could lead to the pages being accessed after
termination. With this change, the driver shall remap a group's shared
page to the dummy page during termination to ensure that accesses to
it will not cause the application to crash, but also these accesses will
be rendered harmless.

For RK, this modification is derived from the kernel_patch_from_Eric_250412
provided by ARM in support case 03504455.
It is originally intended to address the issue
that the GKI of kernel 5.10 does not provide 'zap_vma_ptes'
which the r54 driver depends on.

Change-Id: I28a6946436343d2b44fe7e4df9b4bb8bbd3bafe1
Signed-off-by: Zhen Chen <chenzhen@rock-chips.com>
This commit is contained in:
Zhen Chen
2025-04-12 16:52:56 +08:00
committed by Tao Huang
parent fb91362a23
commit 2e1afa3ce5
3 changed files with 20 additions and 26 deletions

View File

@@ -211,11 +211,6 @@ static void kernel_free_user_io_pages(struct kbase_context *kctx, struct tagged_
kbase_gpu_vm_lock(kctx);
vunmap(user_io_addr);
if (kctx->csf.user_io.vma != NULL) {
zap_vma_ptes(kctx->csf.user_io.vma, kctx->csf.user_io.vma->vm_start,
KBASEP_NUM_CS_USER_IO_PAGES * PAGE_SIZE);
kctx->csf.user_io.vma = NULL;
}
WARN_ON(atomic_read(&kctx->permanent_mapped_pages) < KBASEP_NUM_CS_USER_IO_PAGES);
atomic_sub(KBASEP_NUM_CS_USER_IO_PAGES, &kctx->permanent_mapped_pages);
@@ -1028,6 +1023,13 @@ static void unbind_stopped_queue(struct kbase_context *kctx, struct kbase_queue
queue->group = NULL;
kbase_csf_scheduler_spin_unlock(kctx->kbdev, flags);
/* Ensure that the user I/O pages are no longer accessible */
mutex_lock(&kctx->kbdev->csf.reg_lock);
unmap_mapping_range(kctx->kbdev->csf.db_filp->f_inode->i_mapping,
(loff_t)(queue->db_file_offset << PAGE_SHIFT),
BASEP_QUEUE_NR_MMAP_USER_PAGES * PAGE_SIZE, 1);
mutex_unlock(&kctx->kbdev->csf.reg_lock);
put_user_pages_mmap_handle(kctx, queue);
WARN_ON_ONCE(queue->doorbell_nr != KBASEP_USER_DB_NR_INVALID);
queue->bind_state = KBASE_CSF_QUEUE_UNBOUND;

View File

@@ -927,17 +927,6 @@ struct kbase_csf_event {
spinlock_t lock;
};
/**
* struct kbase_csf_user_io_context - Object containing members to manage the mapping
* of USER io page for a context.
*
* @vma: Pointer to the VMA corresponding to the virtual mapping
* of the USER io page.
*/
struct kbase_csf_user_io_context {
struct vm_area_struct *vma;
};
/**
* struct kbase_csf_user_reg_context - Object containing members to manage the mapping
* of USER Register page for a context.
@@ -997,7 +986,6 @@ struct kbase_csf_user_reg_context {
* @cpu_queue: CPU queue information. Only be available when DEBUG_FS
* is enabled.
* @user_reg: Collective information to support mapping to USER Register page.
* @user_io: Collective information to support mapping to USER IO page.
* @pending_sync_update: Indicates that kbase_csf_scheduler_kthread() should
* handle SYNC_UPDATE event for this context. This would
* be set to false when the work is done. This is used
@@ -1018,7 +1006,6 @@ struct kbase_csf_context {
struct kbase_csf_scheduler_context sched;
struct kbase_csf_cpu_queue_context cpu_queue;
struct kbase_csf_user_reg_context user_reg;
struct kbase_csf_user_io_context user_io;
atomic_t pending_sync_update;
};

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
*
* (C) COPYRIGHT 2010-2024 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2025 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -3440,13 +3440,19 @@ static vm_fault_t kbase_csf_user_io_pages_vm_fault(struct vm_fault *vmf)
output_cpu_addr = input_cpu_addr + PAGE_SIZE;
if (mali_kbase_supports_csg_cs_user_page_allocation(queue->kctx->api_version)) {
if (!queue->group) {
ret = VM_FAULT_SIGBUS;
goto exit;
if (likely(queue->group)) {
input_page_pfn = PFN_DOWN(as_phys_addr_t(queue->group->phys[0]));
output_page_pfn = PFN_DOWN(as_phys_addr_t(queue->group->phys[1]));
} else {
/* This could happen if userspace tries to access this memory
* after the group has already been terminated due to a fault.
* Re-map to the dummy page to render the access harmless.
*/
input_page_pfn =
PFN_DOWN(as_phys_addr_t(kbdev->csf.user_reg.dummy_page));
output_page_pfn =
PFN_DOWN(as_phys_addr_t(kbdev->csf.user_reg.dummy_page));
}
input_page_pfn = PFN_DOWN(as_phys_addr_t(queue->group->phys[0]));
output_page_pfn = PFN_DOWN(as_phys_addr_t(queue->group->phys[1]));
} else {
input_page_pfn = PFN_DOWN(as_phys_addr_t(queue->phys[0]));
output_page_pfn = PFN_DOWN(as_phys_addr_t(queue->phys[1]));
@@ -3541,7 +3547,6 @@ static int kbase_csf_cpu_mmap_user_io_pages(struct kbase_context *kctx, struct v
get_file(vma->vm_file);
/* Also adjust the vm_pgoff */
vma->vm_pgoff = queue->db_file_offset;
kctx->csf.user_io.vma = vma;
return 0;