• Xiaochen Shen's avatar
    x86/resctrl: Fix use-after-free due to inaccurate refcount of rdtgroup · 074fadee
    Xiaochen Shen authored
    There is a race condition in the following scenario which results in an
    use-after-free issue when reading a monitoring file and deleting the
    parent ctrl_mon group concurrently:
    
    Thread 1 calls atomic_inc() to take refcount of rdtgrp and then calls
    kernfs_break_active_protection() to drop the active reference of kernfs
    node in rdtgroup_kn_lock_live().
    
    In Thread 2, kernfs_remove() is a blocking routine. It waits on all sub
    kernfs nodes to drop the active reference when removing all subtree
    kernfs nodes recursively. Thread 2 could block on kernfs_remove() until
    Thread 1 calls kernfs_break_active_protection(). Only after
    kernfs_remove() completes the refcount of rdtgrp could be trusted.
    
    Before Thread 1 calls atomic_inc() and kernfs_break_active_protection(),
    Thread 2 could call kfree() when the refcount of rdtgrp (sentry) is 0
    instead of 1 due to the race.
    
    In Thread 1, in rdtgroup_kn_unlock(), referring to earlier rdtgrp memory
    (rdtgrp->waitcount) which was already freed in Thread 2 results in
    use-after-free issue.
    
    Thread 1 (rdtgroup_mondata_show)  Thread 2 (rdtgroup_rmdir)
    --------------------------------  -------------------------
    rdtgroup_kn_lock_live
      /*
       * kn active protection until
       * kernfs_break_active_protection(kn)
       */
      rdtgrp = kernfs_to_rdtgroup(kn)
                                      rdtgroup_kn_lock_live
                                        atomic_inc(&rdtgrp->waitcount)
                                        mutex_lock
                                      rdtgroup_rmdir_ctrl
                                        free_all_child_rdtgrp
                                          /*
                                           * sentry->waitcount should be 1
                                           * but is 0 now due to the race.
                                           */
                                          kfree(sentry)*[1]
      /*
       * Only after kernfs_remove()
       * completes, the refcount of
       * rdtgrp could be trusted.
       */
      atomic_inc(&rdtgrp->waitcount)
      /* kn->active-- */
      kernfs_break_active_protection(kn)
                                        rdtgroup_ctrl_remove
                                          rdtgrp->flags = RDT_DELETED
                                          /*
                                           * Blocking routine, wait for
                                           * all sub kernfs nodes to drop
                                           * active reference in
                                           * kernfs_break_active_protection.
                                           */
                                          kernfs_remove(rdtgrp->kn)
                                      rdtgroup_kn_unlock
                                        mutex_unlock
                                        atomic_dec_and_test(
                                                    &rdtgrp->waitcount)
                                        && (flags & RDT_DELETED)
                                          kernfs_unbreak_active_protection(kn)
                                          kfree(rdtgrp)
      mutex_lock
    mon_event_read
    rdtgroup_kn_unlock
      mutex_unlock
      /*
       * Use-after-free: refer to earlier rdtgrp
       * memory which was freed in [1].
       */
      atomic_dec_and_test(&rdtgrp->waitcount)
      && (flags & RDT_DELETED)
        /* kn->active++ */
        kernfs_unbreak_active_protection(kn)
        kfree(rdtgrp)
    
    Fix it by moving free_all_child_rdtgrp() to after kernfs_remove() in
    rdtgroup_rmdir_ctrl() to ensure it has the accurate refcount of rdtgrp.
    
    Fixes: f3cbeaca ("x86/intel_rdt/cqm: Add rmdir support")
    Suggested-by: default avatarReinette Chatre <reinette.chatre@intel.com>
    Signed-off-by: default avatarXiaochen Shen <xiaochen.shen@intel.com>
    Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
    Reviewed-by: default avatarReinette Chatre <reinette.chatre@intel.com>
    Reviewed-by: default avatarTony Luck <tony.luck@intel.com>
    Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Cc: stable@vger.kernel.org
    Link: https://lkml.kernel.org/r/1578500886-21771-3-git-send-email-xiaochen.shen@intel.com
    074fadee
rdtgroup.c 76.7 KB