Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: shrinkers: fix double kfree on shrinker name

syzbot is reporting double kfree() at free_prealloced_shrinker() [1], for
destroy_unused_super() calls free_prealloced_shrinker() even if
prealloc_shrinker() returned an error. Explicitly clear shrinker name
when prealloc_shrinker() called kfree().

[roman.gushchin@linux.dev: zero shrinker->name in all cases where shrinker->name is freed]
Link: https://lkml.kernel.org/r/YtgteTnQTgyuKUSY@castle
Link: https://syzkaller.appspot.com/bug?extid=8b481578352d4637f510 [1]
Link: https://lkml.kernel.org/r/ffa62ece-6a42-2644-16cf-0d33ef32c676@I-love.SAKURA.ne.jp
Fixes: e33c267ab70de424 ("mm: shrinkers: provide shrinkers with names")
Reported-by: syzbot <syzbot+8b481578352d4637f510@syzkaller.appspotmail.com>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Tetsuo Handa and committed by
akpm
14773bfa 187e7c41

+8 -2
+1
mm/shrinker_debug.c
··· 251 251 lockdep_assert_held(&shrinker_rwsem); 252 252 253 253 kfree_const(shrinker->name); 254 + shrinker->name = NULL; 254 255 255 256 if (!shrinker->debugfs_entry) 256 257 return;
+7 -2
mm/vmscan.c
··· 644 644 return -ENOMEM; 645 645 646 646 err = __prealloc_shrinker(shrinker); 647 - if (err) 647 + if (err) { 648 648 kfree_const(shrinker->name); 649 + shrinker->name = NULL; 650 + } 649 651 650 652 return err; 651 653 } ··· 662 660 { 663 661 #ifdef CONFIG_SHRINKER_DEBUG 664 662 kfree_const(shrinker->name); 663 + shrinker->name = NULL; 665 664 #endif 666 665 if (shrinker->flags & SHRINKER_MEMCG_AWARE) { 667 666 down_write(&shrinker_rwsem); ··· 707 704 return -ENOMEM; 708 705 709 706 err = __register_shrinker(shrinker); 710 - if (err) 707 + if (err) { 711 708 kfree_const(shrinker->name); 709 + shrinker->name = NULL; 710 + } 712 711 return err; 713 712 } 714 713 #else