From: Srinivasan Shanmugam Date: Thu, 23 Oct 2025 14:24:16 +0000 (+0530) Subject: drm/amdkfd: Fix use-after-free of HMM range in svm_range_validate_and_map() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dfc74e37bdb487eed5ad90d0eac4055f60217fb0;p=thirdparty%2Fkernel%2Flinux.git drm/amdkfd: Fix use-after-free of HMM range in svm_range_validate_and_map() The function svm_range_validate_and_map() was freeing `range` when amdgpu_hmm_range_get_pages() failed. But later, the code still used the same `range` pointer and freed it again. This could cause a use-after-free and double-free issue. The fix sets `range = NULL` right after it is freed and checks for `range` before using or freeing it again. v2: Removed duplicate !r check in the condition for clarity. v3: In amdgpu_hmm_range_get_pages(), when hmm_range_fault() fails, we kvfree(pfns) but leave the pointer in hmm_range->hmm_pfns still pointing to freed memory. The caller (or amdgpu_hmm_range_free(range)) may try to free range->hmm_range.hmm_pfns again, causing a double free, Setting hmm_range->hmm_pfns = NULL immediately after kvfree(pfns) prevents both double free. (Philip) In svm_range_validate_and_map(), When r == 0, it means success → range is not NULL. When r != 0, it means failure → already made range = NULL. So checking both (!r && range) is unnecessary because the moment r == 0, we automatically know range exists and is safe to use. (Philip) Fixes: 737da5363cc0 ("drm/amdgpu: update the functions to use amdgpu version of hmm") Reported by: Dan Carpenter Cc: Philip Yang Cc: Sunil Khatri Cc: Christian König Cc: Alex Deucher Signed-off-by: Srinivasan Shanmugam Reviewed-by: Philip Yang Signed-off-by: Alex Deucher --- diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c index 7e5a09b0bc783..518ca3f4db2bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c @@ -221,6 +221,7 @@ retry: out_free_pfns: kvfree(pfns); + hmm_range->hmm_pfns = NULL; out_free_range: if (r == -EBUSY) r = -EAGAIN; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 729aac81563cb..ffb7b36e577cd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1746,6 +1746,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm, WRITE_ONCE(p->svms.faulting_task, NULL); if (r) { amdgpu_hmm_range_free(range); + range = NULL; pr_debug("failed %d to get svm range pages\n", r); } } else { @@ -1763,7 +1764,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm, svm_range_lock(prange); /* Free backing memory of hmm_range if it was initialized - * Overrride return value to TRY AGAIN only if prior returns + * Override return value to TRY AGAIN only if prior returns * were successful */ if (range && !amdgpu_hmm_range_valid(range) && !r) { @@ -1771,7 +1772,8 @@ static int svm_range_validate_and_map(struct mm_struct *mm, r = -EAGAIN; } /* Free the hmm range */ - amdgpu_hmm_range_free(range); + if (range) + amdgpu_hmm_range_free(range); if (!r && !list_empty(&prange->child_list)) {