lkml.org 
[lkml]   [2017]   [Jul]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 08/15] perf/ring_buffer: convert ring_buffer.refcount to refcount_t
    Date
    atomic_t variables are currently used to implement reference
    counters with the following properties:
    - counter is initialized to 1 using atomic_set()
    - a resource is freed upon counter reaching zero
    - once counter reaches zero, its further
    increments aren't allowed
    - counter schema uses basic atomic operations
    (set, inc, inc_not_zero, dec_and_test, etc.)

    Such atomic variables should be converted to a newly provided
    refcount_t type and API that prevents accidental counter overflows
    and underflows. This is important since overflows and underflows
    can lead to use-after-free situation and be exploitable.

    The variable ring_buffer.refcount is used as pure reference counter.
    Convert it to refcount_t and fix up the operations.

    Suggested-by: Kees Cook <keescook@chromium.org>
    Reviewed-by: David Windsor <dwindsor@gmail.com>
    Reviewed-by: Hans Liljestrand <ishkamiel@gmail.com>
    Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
    ---
    kernel/events/core.c | 4 ++--
    kernel/events/internal.h | 3 ++-
    kernel/events/ring_buffer.c | 2 +-
    3 files changed, 5 insertions(+), 4 deletions(-)

    diff --git a/kernel/events/core.c b/kernel/events/core.c
    index faf9925..9147397 100644
    --- a/kernel/events/core.c
    +++ b/kernel/events/core.c
    @@ -5049,7 +5049,7 @@ struct ring_buffer *ring_buffer_get(struct perf_event *event)
    rcu_read_lock();
    rb = rcu_dereference(event->rb);
    if (rb) {
    - if (!atomic_inc_not_zero(&rb->refcount))
    + if (!refcount_inc_not_zero(&rb->refcount))
    rb = NULL;
    }
    rcu_read_unlock();
    @@ -5059,7 +5059,7 @@ struct ring_buffer *ring_buffer_get(struct perf_event *event)

    void ring_buffer_put(struct ring_buffer *rb)
    {
    - if (!atomic_dec_and_test(&rb->refcount))
    + if (!refcount_dec_and_test(&rb->refcount))
    return;

    WARN_ON_ONCE(!list_empty(&rb->event_list));
    diff --git a/kernel/events/internal.h b/kernel/events/internal.h
    index 486fd78..b8e6fdf 100644
    --- a/kernel/events/internal.h
    +++ b/kernel/events/internal.h
    @@ -3,13 +3,14 @@

    #include <linux/hardirq.h>
    #include <linux/uaccess.h>
    +#include <linux/refcount.h>

    /* Buffer handling */

    #define RING_BUFFER_WRITABLE 0x01

    struct ring_buffer {
    - atomic_t refcount;
    + refcount_t refcount;
    struct rcu_head rcu_head;
    #ifdef CONFIG_PERF_USE_VMALLOC
    struct work_struct work;
    diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
    index ee97196..3353572 100644
    --- a/kernel/events/ring_buffer.c
    +++ b/kernel/events/ring_buffer.c
    @@ -284,7 +284,7 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
    else
    rb->overwrite = 1;

    - atomic_set(&rb->refcount, 1);
    + refcount_set(&rb->refcount, 1);

    INIT_LIST_HEAD(&rb->event_list);
    spin_lock_init(&rb->event_lock);
    --
    2.7.4
    \
     
     \ /
      Last update: 2017-07-18 12:41    [W:3.605 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site