Skip to content

Commit

Permalink
mm/kmemleak.c: wait for scan completion before disabling free
Browse files Browse the repository at this point in the history
A crash is observed when kmemleak_scan accesses the object->pointer,
likely due to the following race.

  TASK A             TASK B                     TASK C
  kmemleak_write
   (with "scan" and
   NOT "scan=on")
  kmemleak_scan()
                     create_object
                     kmem_cache_alloc fails
                     kmemleak_disable
                     kmemleak_do_cleanup
                     kmemleak_free_enabled = 0
                                                kfree
                                                kmemleak_free bails out
                                                 (kmemleak_free_enabled is 0)
                                                slub frees object->pointer
  update_checksum
  crash - object->pointer
   freed (DEBUG_PAGEALLOC)

kmemleak_do_cleanup waits for the scan thread to complete, but not for
direct call to kmemleak_scan via kmemleak_write.  So add a wait for
kmemleak_scan completion before disabling kmemleak_free, and while at it
fix the comment on stop_scan_thread.

[[email protected]: fix stop_scan_thread comment]
  Link: http://lkml.kernel.org/r/[email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Vinayak Menon <[email protected]>
Reviewed-by: Catalin Marinas <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Vinayak Menon authored and torvalds committed Mar 28, 2018
1 parent b213b54 commit 914b6df
Showing 1 changed file with 7 additions and 5 deletions.
12 changes: 7 additions & 5 deletions mm/kmemleak.c
Original file line number Diff line number Diff line change
Expand Up @@ -1657,8 +1657,7 @@ static void start_scan_thread(void)
}

/*
* Stop the automatic memory scanning thread. This function must be called
* with the scan_mutex held.
* Stop the automatic memory scanning thread.
*/
static void stop_scan_thread(void)
{
Expand Down Expand Up @@ -1921,12 +1920,15 @@ static void kmemleak_do_cleanup(struct work_struct *work)
{
stop_scan_thread();

mutex_lock(&scan_mutex);
/*
* Once the scan thread has stopped, it is safe to no longer track
* object freeing. Ordering of the scan thread stopping and the memory
* accesses below is guaranteed by the kthread_stop() function.
* Once it is made sure that kmemleak_scan has stopped, it is safe to no
* longer track object freeing. Ordering of the scan thread stopping and
* the memory accesses below is guaranteed by the kthread_stop()
* function.
*/
kmemleak_free_enabled = 0;
mutex_unlock(&scan_mutex);

if (!kmemleak_found_leaks)
__kmemleak_do_cleanup();
Expand Down

0 comments on commit 914b6df

Please sign in to comment.