Commit 14773bfa authored by Tetsuo Handa's avatar Tetsuo Handa Committed by Andrew Morton
Browse files

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: e33c267a ("mm: shrinkers: provide shrinkers with names")
Reported-by: default avatarsyzbot <syzbot+8b481578352d4637f510@syzkaller.appspotmail.com>
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: default avatarRoman Gushchin <roman.gushchin@linux.dev>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 187e7c41
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -251,6 +251,7 @@ void shrinker_debugfs_remove(struct shrinker *shrinker)
	lockdep_assert_held(&shrinker_rwsem);
	lockdep_assert_held(&shrinker_rwsem);


	kfree_const(shrinker->name);
	kfree_const(shrinker->name);
	shrinker->name = NULL;


	if (!shrinker->debugfs_entry)
	if (!shrinker->debugfs_entry)
		return;
		return;
+7 −2
Original line number Original line Diff line number Diff line
@@ -644,8 +644,10 @@ int prealloc_shrinker(struct shrinker *shrinker, const char *fmt, ...)
		return -ENOMEM;
		return -ENOMEM;


	err = __prealloc_shrinker(shrinker);
	err = __prealloc_shrinker(shrinker);
	if (err)
	if (err) {
		kfree_const(shrinker->name);
		kfree_const(shrinker->name);
		shrinker->name = NULL;
	}


	return err;
	return err;
}
}
@@ -660,6 +662,7 @@ void free_prealloced_shrinker(struct shrinker *shrinker)
{
{
#ifdef CONFIG_SHRINKER_DEBUG
#ifdef CONFIG_SHRINKER_DEBUG
	kfree_const(shrinker->name);
	kfree_const(shrinker->name);
	shrinker->name = NULL;
#endif
#endif
	if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
	if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
		down_write(&shrinker_rwsem);
		down_write(&shrinker_rwsem);
@@ -704,8 +707,10 @@ int register_shrinker(struct shrinker *shrinker, const char *fmt, ...)
		return -ENOMEM;
		return -ENOMEM;


	err = __register_shrinker(shrinker);
	err = __register_shrinker(shrinker);
	if (err)
	if (err) {
		kfree_const(shrinker->name);
		kfree_const(shrinker->name);
		shrinker->name = NULL;
	}
	return err;
	return err;
}
}
#else
#else