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 uprobe.ref is used as pure reference counter.
Convert it to refcount_t and fix up the operations.

Suggested-by: Kees Cook <keesc...@chromium.org>
Reviewed-by: David Windsor <dwind...@gmail.com>
Reviewed-by: Hans Liljestrand <ishkam...@gmail.com>
Signed-off-by: Elena Reshetova <elena.reshet...@intel.com>
---
 kernel/events/uprobes.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 8d42d8f..3514b42 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -66,7 +66,7 @@ static struct percpu_rw_semaphore dup_mmap_sem;
 
 struct uprobe {
        struct rb_node          rb_node;        /* node in the rb tree */
-       atomic_t                ref;
+       refcount_t              ref;
        struct rw_semaphore     register_rwsem;
        struct rw_semaphore     consumer_rwsem;
        struct list_head        pending_list;
@@ -371,13 +371,13 @@ set_orig_insn(struct arch_uprobe *auprobe, struct 
mm_struct *mm, unsigned long v
 
 static struct uprobe *get_uprobe(struct uprobe *uprobe)
 {
-       atomic_inc(&uprobe->ref);
+       refcount_inc(&uprobe->ref);
        return uprobe;
 }
 
 static void put_uprobe(struct uprobe *uprobe)
 {
-       if (atomic_dec_and_test(&uprobe->ref))
+       if (refcount_dec_and_test(&uprobe->ref))
                kfree(uprobe);
 }
 
@@ -459,7 +459,7 @@ static struct uprobe *__insert_uprobe(struct uprobe *uprobe)
        rb_link_node(&uprobe->rb_node, parent, p);
        rb_insert_color(&uprobe->rb_node, &uprobes_tree);
        /* get access + creation ref */
-       atomic_set(&uprobe->ref, 2);
+       refcount_set(&uprobe->ref, 2);
 
        return u;
 }
-- 
2.7.4

Reply via email to