On 20/07/2026 12:49, Osama Abdelkader wrote:
> iface_fw_to_cpu_addr() only checks that the firmware-provided MCU virtual
> address points inside the shared section. The returned pointer is later
> used as a full firmware interface structure, so accepting an address near
> the end of the shared section can still lead to out-of-bounds accesses.
> 
> Pass the expected object size to iface_fw_to_cpu_addr() and reject ranges
> that do not fit entirely in the shared section.
> 
> Fixes: 2718d91816ee ("drm/panthor: Add the FW logical block")
> Cc: [email protected]
> Signed-off-by: Osama Abdelkader <[email protected]>

Reviewed-by: Steven Price <[email protected]>

I'll push this to drm-misc-fixes.

Thanks,
Steve

> ---
>  drivers/gpu/drm/panthor/panthor_fw.c | 30 ++++++++++++++++++---------
>  1 file changed, 20 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.c 
> b/drivers/gpu/drm/panthor/panthor_fw.c
> index 9d0e1fafdce2..eee2bc7e8541 100644
> --- a/drivers/gpu/drm/panthor/panthor_fw.c
> +++ b/drivers/gpu/drm/panthor/panthor_fw.c
> @@ -870,18 +870,24 @@ static int panthor_fw_load(struct panthor_device *ptdev)
>   * iface_fw_to_cpu_addr() - Turn an MCU address into a CPU address
>   * @ptdev: Device.
>   * @mcu_va: MCU address.
> + * @size: Size of the object pointed to by @mcu_va.
>   *
> - * Return: NULL if the address is not part of the shared section, non-NULL 
> otherwise.
> + * Return: NULL if the object is not part of the shared section, non-NULL 
> otherwise.
>   */
> -static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va)
> +static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va, 
> size_t size)
>  {
>       u64 shared_mem_start = 
> panthor_kernel_bo_gpuva(ptdev->fw->shared_section->mem);
> -     u64 shared_mem_end = shared_mem_start +
> -                          
> panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
> -     if (mcu_va < shared_mem_start || mcu_va >= shared_mem_end)
> +     size_t shared_mem_size = 
> panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
> +     u64 offset;
> +
> +     if (mcu_va < shared_mem_start)
> +             return NULL;
> +
> +     offset = mcu_va - shared_mem_start;
> +     if (offset > shared_mem_size || size > shared_mem_size - offset)
>               return NULL;
>  
> -     return ptdev->fw->shared_section->mem->kmap + (mcu_va - 
> shared_mem_start);
> +     return ptdev->fw->shared_section->mem->kmap + offset;
>  }
>  
>  static int panthor_init_cs_iface(struct panthor_device *ptdev,
> @@ -906,8 +912,10 @@ static int panthor_init_cs_iface(struct panthor_device 
> *ptdev,
>  
>       spin_lock_init(&cs_iface->lock);
>       cs_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset;
> -     cs_iface->input = iface_fw_to_cpu_addr(ptdev, 
> cs_iface->control->input_va);
> -     cs_iface->output = iface_fw_to_cpu_addr(ptdev, 
> cs_iface->control->output_va);
> +     cs_iface->input = iface_fw_to_cpu_addr(ptdev, 
> cs_iface->control->input_va,
> +                                            sizeof(*cs_iface->input));
> +     cs_iface->output = iface_fw_to_cpu_addr(ptdev, 
> cs_iface->control->output_va,
> +                                             sizeof(*cs_iface->output));
>  
>       if (!cs_iface->input || !cs_iface->output) {
>               drm_err(&ptdev->base, "Invalid stream control interface 
> input/output VA");
> @@ -957,8 +965,10 @@ static int panthor_init_csg_iface(struct panthor_device 
> *ptdev,
>  
>       spin_lock_init(&csg_iface->lock);
>       csg_iface->control = ptdev->fw->shared_section->mem->kmap + 
> iface_offset;
> -     csg_iface->input = iface_fw_to_cpu_addr(ptdev, 
> csg_iface->control->input_va);
> -     csg_iface->output = iface_fw_to_cpu_addr(ptdev, 
> csg_iface->control->output_va);
> +     csg_iface->input = iface_fw_to_cpu_addr(ptdev, 
> csg_iface->control->input_va,
> +                                             sizeof(*csg_iface->input));
> +     csg_iface->output = iface_fw_to_cpu_addr(ptdev, 
> csg_iface->control->output_va,
> +                                              sizeof(*csg_iface->output));
>  
>       if (csg_iface->control->stream_num < MIN_CS_PER_CSG ||
>           csg_iface->control->stream_num > MAX_CS_PER_CSG)
> @@ -1015,8 +1025,10 @@ static int panthor_fw_init_ifaces(struct 
> panthor_device *ptdev)
>               return -EINVAL;
>       }
>  
> -     glb_iface->input = iface_fw_to_cpu_addr(ptdev, 
> glb_iface->control->input_va);
> -     glb_iface->output = iface_fw_to_cpu_addr(ptdev, 
> glb_iface->control->output_va);
> +     glb_iface->input = iface_fw_to_cpu_addr(ptdev, 
> glb_iface->control->input_va,
> +                                             sizeof(*glb_iface->input));
> +     glb_iface->output = iface_fw_to_cpu_addr(ptdev, 
> glb_iface->control->output_va,
> +                                              sizeof(*glb_iface->output));
>       if (!glb_iface->input || !glb_iface->output) {
>               drm_err(&ptdev->base, "Invalid global control interface 
> input/output VA");
>               return -EINVAL;

Reply via email to