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 | |
| 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>
| -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)); |
