mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
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: 737da5363c ("drm/amdgpu: update the functions to use amdgpu version of hmm")
Reported by: Dan Carpenter <dan.carpenter@linaro.org>
Cc: Philip Yang <Philip.Yang@amd.com>
Cc: Sunil Khatri <sunil.khatri@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
Reviewed-by: Philip Yang<Philip.Yang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
1017e393ad
commit
dfc74e37bd
|
|
@ -221,6 +221,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
|
||||
out_free_pfns:
|
||||
kvfree(pfns);
|
||||
hmm_range->hmm_pfns = NULL;
|
||||
out_free_range:
|
||||
if (r == -EBUSY)
|
||||
r = -EAGAIN;
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user