vmur: convert urdev.ref_count from atomic_t to refcount_t
authorElena Reshetova <elena.reshetova@intel.com>
Fri, 20 Oct 2017 07:47:48 +0000 (10:47 +0300)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 26 Oct 2017 06:36:38 +0000 (08:36 +0200)
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 urdev.ref_count 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>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/char/vmur.c
drivers/s390/char/vmur.h

index a50cf93..fa90ef0 100644 (file)
@@ -110,7 +110,7 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
        mutex_init(&urd->io_mutex);
        init_waitqueue_head(&urd->wait);
        spin_lock_init(&urd->open_lock);
-       atomic_set(&urd->ref_count,  1);
+       refcount_set(&urd->ref_count,  1);
        urd->cdev = cdev;
        get_device(&cdev->dev);
        return urd;
@@ -126,7 +126,7 @@ static void urdev_free(struct urdev *urd)
 
 static void urdev_get(struct urdev *urd)
 {
-       atomic_inc(&urd->ref_count);
+       refcount_inc(&urd->ref_count);
 }
 
 static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
@@ -159,7 +159,7 @@ static struct urdev *urdev_get_from_devno(u16 devno)
 
 static void urdev_put(struct urdev *urd)
 {
-       if (atomic_dec_and_test(&urd->ref_count))
+       if (refcount_dec_and_test(&urd->ref_count))
                urdev_free(urd);
 }
 
@@ -945,7 +945,7 @@ static int ur_set_offline_force(struct ccw_device *cdev, int force)
                rc = -EBUSY;
                goto fail_urdev_put;
        }
-       if (!force && (atomic_read(&urd->ref_count) > 2)) {
+       if (!force && (refcount_read(&urd->ref_count) > 2)) {
                /* There is still a user of urd (e.g. ur_open) */
                TRACE("ur_set_offline: BUSY\n");
                rc = -EBUSY;
index fa320ad..35ea9d1 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef _VMUR_H_
 #define _VMUR_H_
 
+#include <linux/refcount.h>
+
 #define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */
 #define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */
 /*
@@ -69,7 +71,7 @@ struct urdev {
        size_t reclen;                  /* Record length for *write* CCWs */
        int class;                      /* VM device class */
        int io_request_rc;              /* return code from I/O request */
-       atomic_t ref_count;             /* reference counter */
+       refcount_t ref_count;           /* reference counter */
        wait_queue_head_t wait;         /* wait queue to serialize open */
        int open_flag;                  /* "urdev is open" flag */
        spinlock_t open_lock;           /* serialize critical sections */