summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Limonciello <mario.limonciello@amd.com>2026-07-09 19:16:03 -0500
committerMario Limonciello <superm1@gmail.com>2026-08-13 15:22:46 -0500
commitc9b52c358979dff8d9117b95178dee5fbcd5b017 (patch)
tree91fe646138aaa36365726d0d058439a14483b118
parentb629efddb7597d7e741c46983ac49dabff6c14d4 (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.c21
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++)