Skip to content

Commit 253a496

Browse files
daxtenstorvalds
authored andcommitted
kasan: don't assume percpu shadow allocations will succeed
syzkaller and the fault injector showed that I was wrong to assume that we could ignore percpu shadow allocation failures. Handle failures properly. Merge all the allocated areas back into the free list and release the shadow, then clean up and return NULL. The shadow is released unconditionally, which relies upon the fact that the release function is able to tolerate pages not being present. Also clean up shadows in the recovery path - currently they are not released, which leaks a bit of memory. Link: http://lkml.kernel.org/r/[email protected] Fixes: 3c5c3cf ("kasan: support backing vmalloc space with real shadow memory") Signed-off-by: Daniel Axtens <[email protected]> Reported-by: [email protected] Reported-by: [email protected] Reviewed-by: Andrey Ryabinin <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Qian Cai <[email protected]> Cc: Uladzislau Rezki (Sony) <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent e218f1c commit 253a496

File tree

1 file changed

+38
-10
lines changed

1 file changed

+38
-10
lines changed

mm/vmalloc.c

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3288,7 +3288,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
32883288
struct vmap_area **vas, *va;
32893289
struct vm_struct **vms;
32903290
int area, area2, last_area, term_area;
3291-
unsigned long base, start, size, end, last_end;
3291+
unsigned long base, start, size, end, last_end, orig_start, orig_end;
32923292
bool purged = false;
32933293
enum fit_type type;
32943294

@@ -3418,6 +3418,15 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
34183418

34193419
spin_unlock(&free_vmap_area_lock);
34203420

3421+
/* populate the kasan shadow space */
3422+
for (area = 0; area < nr_vms; area++) {
3423+
if (kasan_populate_vmalloc(vas[area]->va_start, sizes[area]))
3424+
goto err_free_shadow;
3425+
3426+
kasan_unpoison_vmalloc((void *)vas[area]->va_start,
3427+
sizes[area]);
3428+
}
3429+
34213430
/* insert all vm's */
34223431
spin_lock(&vmap_area_lock);
34233432
for (area = 0; area < nr_vms; area++) {
@@ -3428,13 +3437,6 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
34283437
}
34293438
spin_unlock(&vmap_area_lock);
34303439

3431-
/* populate the shadow space outside of the lock */
3432-
for (area = 0; area < nr_vms; area++) {
3433-
/* assume success here */
3434-
kasan_populate_vmalloc(vas[area]->va_start, sizes[area]);
3435-
kasan_unpoison_vmalloc((void *)vms[area]->addr, sizes[area]);
3436-
}
3437-
34383440
kfree(vas);
34393441
return vms;
34403442

@@ -3446,8 +3448,12 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
34463448
* and when pcpu_get_vm_areas() is success.
34473449
*/
34483450
while (area--) {
3449-
merge_or_add_vmap_area(vas[area], &free_vmap_area_root,
3450-
&free_vmap_area_list);
3451+
orig_start = vas[area]->va_start;
3452+
orig_end = vas[area]->va_end;
3453+
va = merge_or_add_vmap_area(vas[area], &free_vmap_area_root,
3454+
&free_vmap_area_list);
3455+
kasan_release_vmalloc(orig_start, orig_end,
3456+
va->va_start, va->va_end);
34513457
vas[area] = NULL;
34523458
}
34533459

@@ -3482,6 +3488,28 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
34823488
kfree(vas);
34833489
kfree(vms);
34843490
return NULL;
3491+
3492+
err_free_shadow:
3493+
spin_lock(&free_vmap_area_lock);
3494+
/*
3495+
* We release all the vmalloc shadows, even the ones for regions that
3496+
* hadn't been successfully added. This relies on kasan_release_vmalloc
3497+
* being able to tolerate this case.
3498+
*/
3499+
for (area = 0; area < nr_vms; area++) {
3500+
orig_start = vas[area]->va_start;
3501+
orig_end = vas[area]->va_end;
3502+
va = merge_or_add_vmap_area(vas[area], &free_vmap_area_root,
3503+
&free_vmap_area_list);
3504+
kasan_release_vmalloc(orig_start, orig_end,
3505+
va->va_start, va->va_end);
3506+
vas[area] = NULL;
3507+
kfree(vms[area]);
3508+
}
3509+
spin_unlock(&free_vmap_area_lock);
3510+
kfree(vas);
3511+
kfree(vms);
3512+
return NULL;
34853513
}
34863514

34873515
/**

0 commit comments

Comments
 (0)