Re: rcu_sync_dtor() warning question

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jul 26, 2024 at 03:54:28PM +0200, Christian Brauner wrote:
> Hey,
> 
> I could use some help with understanding a bug related to rcu that was
> reported today. It first seems to have shown up on the 25th of July:
> 
> https://syzkaller.appspot.com/bug?extid=20d7e439f76bbbd863a7
> 
> We seem to be hitting the WARN_ON_ONCE() in:
> 
> void rcu_sync_dtor(struct rcu_sync *rsp)
> {
>         int gp_state;
> 
>         WARN_ON_ONCE(READ_ONCE(rsp->gp_state) == GP_PASSED);
> 
> from destroy_super_work() which gets called when a superblock is really freed.
> 
> If the superblock has been visible in userspace we do it via call_rcu():
> 
> static void destroy_super_work(struct work_struct *work)
> {
>         struct super_block *s = container_of(work, struct super_block,
>                                                         destroy_work);
>         fsnotify_sb_free(s);
>         security_sb_free(s);
>         put_user_ns(s->s_user_ns);
>         kfree(s->s_subtype);
>         for (int i = 0; i < SB_FREEZE_LEVELS; i++)
>                 percpu_free_rwsem(&s->s_writers.rw_sem[i]);
>         kfree(s);
> }
> 
> static void destroy_super_rcu(struct rcu_head *head)
> {
>         struct super_block *s = container_of(head, struct super_block, rcu);
>         INIT_WORK(&s->destroy_work, destroy_super_work);
>         schedule_work(&s->destroy_work);
> }
> 
> And I'm really confused because I don't understand the details for sync
> rcu enough to come up with a clear problem statement even. Could someone
> please explain what the WARN_ON_ONCE() is about?

If I am not too confused (and Oleg will correct me if I am), this is
checking a use-after-free error.  A given rcu_sync structure normally
transitions from GP_IDLE->GP_ENTER->GP_PASSED->GP_EXIT->GP_IDLE, with
possible side-trips from the GP_EXIT state through GP_REPLAY and back
to GP_EXIT in special cases such as during early boot.

One way that this can happen is calling percpu_free_rwsem() without
having previously done the percpu_up_write() needed to match an earlier
percpu_down_write().  I don't see any other way that this can happen
right off-hand, but someone might have added something, or I might be
suffering a failure of imagination.

> (I had been wondering if this is related to commit 7180f8d91fcb ("vfs:
> add rcu-based find_inode variants for iget ops") and the fix in commit
> 5bc9ad78c2f8 ("vfs: handle __wait_on_freeing_inode() and evict() race")
> but I don't see how.)

I don't see how either, unless it introduced some timing change
that made the scenario above more probable.

> Thanks for taking a look!

Hope this helps!  If not, you know where to find me.  ;-)

							Thanx, Paul




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux