diff options
| author | Mario Limonciello <mario.limonciello@amd.com> | 2026-07-09 19:16:03 -0500 |
|---|---|---|
| committer | Mario Limonciello <superm1@gmail.com> | 2026-08-13 15:22:46 -0500 |
| commit | c9b52c358979dff8d9117b95178dee5fbcd5b017 (patch) | |
| tree | 91fe646138aaa36365726d0d058439a14483b118 | |
| parent | b629efddb7597d7e741c46983ac49dabff6c14d4 (diff) | |
amdgpu: bound alloca sizes in CS submission paths
Several command-submission helpers compute alloca() sizes from
caller-controlled uint32_t counts (number_of_ibs, number_of_dependencies,
fence_count and num_chunks) without any upper bound. A very large count
produces a multi-megabyte stack allocation that can jump over the stack
guard page (stack clash); on 32-bit the size multiplication can also wrap,
producing a tiny reservation that is subsequently overrun by the
full-count copy. The trailing "if (!dependencies)" style NULL checks after
alloca() never trigger and provide no protection.
Reject clearly out-of-range counts with -EINVAL before the corresponding
alloca(). The number of IBs is limited to the existing
AMDGPU_CS_MAX_IBS_PER_SUBMIT; dependencies, fences and raw chunk counts
are limited to a new AMDGPU_CS_MAX_ALLOCA_COUNT that is far above any
legitimate request. The raw chunk paths also reject non-positive counts so
a negative int cannot be sign-extended into a huge allocation.
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
| -rw-r--r-- | amdgpu/amdgpu_cs.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/amdgpu/amdgpu_cs.c b/amdgpu/amdgpu_cs.c index e138bc73..9e11cebe 100644 --- a/amdgpu/amdgpu_cs.c +++ b/amdgpu/amdgpu_cs.c @@ -39,6 +39,16 @@ static int amdgpu_cs_unreference_sem(amdgpu_semaphore_handle sem); static int amdgpu_cs_reset_sem(amdgpu_semaphore_handle sem); +/* + * Upper bound for caller-controlled counts that are used to size on-stack + * alloca() buffers. Without a cap a large count produces a multi-megabyte + * allocation that can skip the stack guard page (stack clash), and on 32-bit + * the size multiplication can overflow, yielding a tiny buffer that is then + * overrun by the full-count copy. The number of IBs has its own, tighter + * limit (AMDGPU_CS_MAX_IBS_PER_SUBMIT). + */ +#define AMDGPU_CS_MAX_ALLOCA_COUNT 4096 + /** * Create command submission context * @@ -272,6 +282,10 @@ static int amdgpu_cs_submit_one(amdgpu_context_handle context, return -EINVAL; if (ibs_request->ring >= AMDGPU_CS_MAX_RINGS) return -EINVAL; + if (ibs_request->number_of_ibs > AMDGPU_CS_MAX_IBS_PER_SUBMIT) + return -EINVAL; + if (ibs_request->number_of_dependencies > AMDGPU_CS_MAX_ALLOCA_COUNT) + return -EINVAL; if (ibs_request->number_of_ibs == 0) { ibs_request->seq_no = AMDGPU_NULL_SUBMIT_SEQ; return 0; @@ -522,6 +536,8 @@ static int amdgpu_ioctl_wait_fences(struct amdgpu_cs_fence *fences, int r; uint32_t i; + if (fence_count > AMDGPU_CS_MAX_ALLOCA_COUNT) + return -EINVAL; drm_fences = alloca(sizeof(struct drm_amdgpu_fence) * fence_count); for (i = 0; i < fence_count; i++) { drm_fences[i].ctx_id = fences[i].context->id; @@ -909,7 +925,7 @@ drm_public int amdgpu_cs_submit_raw(amdgpu_device_handle dev, union drm_amdgpu_cs cs; uint64_t *chunk_array; int i, r; - if (num_chunks == 0) + if (num_chunks < 1 || num_chunks > AMDGPU_CS_MAX_ALLOCA_COUNT) return -EINVAL; memset(&cs, 0, sizeof(cs)); @@ -941,6 +957,9 @@ drm_public int amdgpu_cs_submit_raw2(amdgpu_device_handle dev, uint64_t *chunk_array; int i, r; + if (num_chunks < 1 || num_chunks > AMDGPU_CS_MAX_ALLOCA_COUNT) + return -EINVAL; + memset(&cs, 0, sizeof(cs)); chunk_array = alloca(sizeof(uint64_t) * num_chunks); for (i = 0; i < num_chunks; i++) |
