Skip to content

Commit

Permalink
drm/amdgpu/psp: prevent page fault by checking write_frame address(v4)
Browse files Browse the repository at this point in the history
 - Prevent a possible buffer overflow when updating the ring buffer by
    bounds checking the command frame against the available space in the
    ring buffer.

 v2: update the ring_buffer_end address
 v3: update the commit log
 v4: squash in print fix (Michel)

Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Evan Quan authored and Alex Deucher committed Oct 26, 2017
1 parent 0722382 commit 4694257
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
14 changes: 12 additions & 2 deletions drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ int psp_v10_0_cmd_submit(struct psp_context *psp,
unsigned int psp_write_ptr_reg = 0;
struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem;
struct psp_ring *ring = &psp->km_ring;
struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem;
struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start +
ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1;
struct amdgpu_device *adev = psp->adev;
uint32_t ring_size_dw = ring->ring_size / 4;
uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4;
Expand All @@ -266,9 +269,16 @@ int psp_v10_0_cmd_submit(struct psp_context *psp,

/* Update KM RB frame pointer to new frame */
if ((psp_write_ptr_reg % ring_size_dw) == 0)
write_frame = ring->ring_mem;
write_frame = ring_buffer_start;
else
write_frame = ring->ring_mem + (psp_write_ptr_reg / rb_frame_size_dw);
write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw);
/* Check invalid write_frame ptr address */
if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) {
DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n",
ring_buffer_start, ring_buffer_end, write_frame);
DRM_ERROR("write_frame is pointing to address out of bounds\n");
return -EINVAL;
}

/* Initialize KM RB frame */
memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame));
Expand Down
14 changes: 12 additions & 2 deletions drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ int psp_v3_1_cmd_submit(struct psp_context *psp,
unsigned int psp_write_ptr_reg = 0;
struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem;
struct psp_ring *ring = &psp->km_ring;
struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem;
struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start +
ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1;
struct amdgpu_device *adev = psp->adev;
uint32_t ring_size_dw = ring->ring_size / 4;
uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4;
Expand All @@ -378,9 +381,16 @@ int psp_v3_1_cmd_submit(struct psp_context *psp,
/* write_frame ptr increments by size of rb_frame in bytes */
/* psp_write_ptr_reg increments by size of rb_frame in DWORDs */
if ((psp_write_ptr_reg % ring_size_dw) == 0)
write_frame = ring->ring_mem;
write_frame = ring_buffer_start;
else
write_frame = ring->ring_mem + (psp_write_ptr_reg / rb_frame_size_dw);
write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw);
/* Check invalid write_frame ptr address */
if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) {
DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n",
ring_buffer_start, ring_buffer_end, write_frame);
DRM_ERROR("write_frame is pointing to address out of bounds\n");
return -EINVAL;
}

/* Initialize KM RB frame */
memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame));
Expand Down

0 comments on commit 4694257

Please sign in to comment.