diff options
author | Evan Quan <evan.quan@amd.com> | 2017-10-16 04:51:28 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2017-10-25 23:09:38 -0400 |
commit | 4694257e7d4757fedaa8dcd18bb5ff52e76a2765 (patch) | |
tree | 7495d845c5878ac1d2497156d5705787bad30df0 /drivers/gpu/drm/amd | |
parent | 0722382dcc4fd4e53c12db2c2eda9c5c9c903432 (diff) |
drm/amdgpu/psp: prevent page fault by checking write_frame address(v4)
- 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>
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/psp_v10_0.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/psp_v3_1.c | 14 |
2 files changed, 24 insertions, 4 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index dea7c909ca5f..4e20d91d5d50 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c | |||
@@ -257,6 +257,9 @@ int psp_v10_0_cmd_submit(struct psp_context *psp, | |||
257 | unsigned int psp_write_ptr_reg = 0; | 257 | unsigned int psp_write_ptr_reg = 0; |
258 | struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; | 258 | struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; |
259 | struct psp_ring *ring = &psp->km_ring; | 259 | struct psp_ring *ring = &psp->km_ring; |
260 | struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; | ||
261 | struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + | ||
262 | ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; | ||
260 | struct amdgpu_device *adev = psp->adev; | 263 | struct amdgpu_device *adev = psp->adev; |
261 | uint32_t ring_size_dw = ring->ring_size / 4; | 264 | uint32_t ring_size_dw = ring->ring_size / 4; |
262 | uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; | 265 | uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; |
@@ -266,9 +269,16 @@ int psp_v10_0_cmd_submit(struct psp_context *psp, | |||
266 | 269 | ||
267 | /* Update KM RB frame pointer to new frame */ | 270 | /* Update KM RB frame pointer to new frame */ |
268 | if ((psp_write_ptr_reg % ring_size_dw) == 0) | 271 | if ((psp_write_ptr_reg % ring_size_dw) == 0) |
269 | write_frame = ring->ring_mem; | 272 | write_frame = ring_buffer_start; |
270 | else | 273 | else |
271 | write_frame = ring->ring_mem + (psp_write_ptr_reg / rb_frame_size_dw); | 274 | write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); |
275 | /* Check invalid write_frame ptr address */ | ||
276 | if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { | ||
277 | DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", | ||
278 | ring_buffer_start, ring_buffer_end, write_frame); | ||
279 | DRM_ERROR("write_frame is pointing to address out of bounds\n"); | ||
280 | return -EINVAL; | ||
281 | } | ||
272 | 282 | ||
273 | /* Initialize KM RB frame */ | 283 | /* Initialize KM RB frame */ |
274 | memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); | 284 | memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); |
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index cee5c396b277..c7bcfe8e286c 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c | |||
@@ -367,6 +367,9 @@ int psp_v3_1_cmd_submit(struct psp_context *psp, | |||
367 | unsigned int psp_write_ptr_reg = 0; | 367 | unsigned int psp_write_ptr_reg = 0; |
368 | struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; | 368 | struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; |
369 | struct psp_ring *ring = &psp->km_ring; | 369 | struct psp_ring *ring = &psp->km_ring; |
370 | struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; | ||
371 | struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + | ||
372 | ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; | ||
370 | struct amdgpu_device *adev = psp->adev; | 373 | struct amdgpu_device *adev = psp->adev; |
371 | uint32_t ring_size_dw = ring->ring_size / 4; | 374 | uint32_t ring_size_dw = ring->ring_size / 4; |
372 | uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; | 375 | uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; |
@@ -378,9 +381,16 @@ int psp_v3_1_cmd_submit(struct psp_context *psp, | |||
378 | /* write_frame ptr increments by size of rb_frame in bytes */ | 381 | /* write_frame ptr increments by size of rb_frame in bytes */ |
379 | /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ | 382 | /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ |
380 | if ((psp_write_ptr_reg % ring_size_dw) == 0) | 383 | if ((psp_write_ptr_reg % ring_size_dw) == 0) |
381 | write_frame = ring->ring_mem; | 384 | write_frame = ring_buffer_start; |
382 | else | 385 | else |
383 | write_frame = ring->ring_mem + (psp_write_ptr_reg / rb_frame_size_dw); | 386 | write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); |
387 | /* Check invalid write_frame ptr address */ | ||
388 | if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { | ||
389 | DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", | ||
390 | ring_buffer_start, ring_buffer_end, write_frame); | ||
391 | DRM_ERROR("write_frame is pointing to address out of bounds\n"); | ||
392 | return -EINVAL; | ||
393 | } | ||
384 | 394 | ||
385 | /* Initialize KM RB frame */ | 395 | /* Initialize KM RB frame */ |
386 | memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); | 396 | memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); |