lkml.org 
[lkml]   [2022]   [Apr]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.17 054/343] ref_tracker: implement use-after-free detection
    Date
    From: Eric Dumazet <edumazet@google.com>

    [ Upstream commit e3ececfe668facd87d920b608349a32607060e66 ]

    Whenever ref_tracker_dir_init() is called, mark the struct ref_tracker_dir
    as dead.

    Test the dead status from ref_tracker_alloc() and ref_tracker_free()

    This should detect buggy dev_put()/dev_hold() happening too late
    in netdevice dismantle process.

    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    include/linux/ref_tracker.h | 2 ++
    lib/ref_tracker.c | 5 +++++
    2 files changed, 7 insertions(+)

    diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
    index 60f3453be23e..a443abda937d 100644
    --- a/include/linux/ref_tracker.h
    +++ b/include/linux/ref_tracker.h
    @@ -13,6 +13,7 @@ struct ref_tracker_dir {
    spinlock_t lock;
    unsigned int quarantine_avail;
    refcount_t untracked;
    + bool dead;
    struct list_head list; /* List of active trackers */
    struct list_head quarantine; /* List of dead trackers */
    #endif
    @@ -26,6 +27,7 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
    INIT_LIST_HEAD(&dir->quarantine);
    spin_lock_init(&dir->lock);
    dir->quarantine_avail = quarantine_count;
    + dir->dead = false;
    refcount_set(&dir->untracked, 1);
    stack_depot_init();
    }
    diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
    index a6789c0c626b..32ff6bd497f8 100644
    --- a/lib/ref_tracker.c
    +++ b/lib/ref_tracker.c
    @@ -20,6 +20,7 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
    unsigned long flags;
    bool leak = false;

    + dir->dead = true;
    spin_lock_irqsave(&dir->lock, flags);
    list_for_each_entry_safe(tracker, n, &dir->quarantine, head) {
    list_del(&tracker->head);
    @@ -72,6 +73,8 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir,
    gfp_t gfp_mask = gfp;
    unsigned long flags;

    + WARN_ON_ONCE(dir->dead);
    +
    if (gfp & __GFP_DIRECT_RECLAIM)
    gfp_mask |= __GFP_NOFAIL;
    *trackerp = tracker = kzalloc(sizeof(*tracker), gfp_mask);
    @@ -100,6 +103,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir,
    unsigned int nr_entries;
    unsigned long flags;

    + WARN_ON_ONCE(dir->dead);
    +
    if (!tracker) {
    refcount_dec(&dir->untracked);
    return -EEXIST;
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-04-12 10:43    [W:4.018 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site