Message ID | 1488810076-3754-13-git-send-email-elena.reshetova@intel.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
Hi Elena, On Mon, Mar 06, 2017 at 04:20:59PM +0200, Elena Reshetova wrote: > refcount_t type and corresponding API should be > used instead of atomic_t when the variable is used as > a reference counter. This allows to avoid accidental > refcounter overflows that might lead to use-after-free > situations. > > Signed-off-by: Elena Reshetova <elena.reshetova@intel.com> > Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com> > Signed-off-by: Kees Cook <keescook@chromium.org> > Signed-off-by: David Windsor <dwindsor@gmail.com> > --- ... > @@ -1688,7 +1689,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) > "failed to register video device!\n"); > break; > } > - atomic_inc(&dev->num_channels); > + refcount_set(&dev->num_channels, 1); That's not right. The loop runs four iterations and the value after the loop should be indeed the number of channels. atomic_t isn't really used for reference counting here, but storing out how many "channels" there are per hardware device, with maximum number of four (4). I'd leave this driver using atomic_t. > v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", > video_device_node_name(&vc->vdev)); >
> Hi Elena, > > On Mon, Mar 06, 2017 at 04:20:59PM +0200, Elena Reshetova wrote: > > refcount_t type and corresponding API should be > > used instead of atomic_t when the variable is used as > > a reference counter. This allows to avoid accidental > > refcounter overflows that might lead to use-after-free > > situations. > > > > Signed-off-by: Elena Reshetova <elena.reshetova@intel.com> > > Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com> > > Signed-off-by: Kees Cook <keescook@chromium.org> > > Signed-off-by: David Windsor <dwindsor@gmail.com> > > --- > ... > > @@ -1688,7 +1689,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) > > "failed to register > video device!\n"); > > break; > > } > > - atomic_inc(&dev->num_channels); > > + refcount_set(&dev->num_channels, 1); > > That's not right. The loop runs four iterations and the value after the > loop should be indeed the number of channels. Oh, yes, I was blind here, sorry. The problem why it cannot be left as inc is because it would do increment from zero here, which is not allowed by refcount_t interface. > atomic_t isn't really used for reference counting here, but storing out how > many "channels" there are per hardware device, with maximum number of four > (4). I'd leave this driver using atomic_t. Yes, sounds like the best thing to do. I will drop this patch. Thank you for reviews! Best Regards, Elena. > > > v4l2_info(&dev->v4l2_dev, "V4L2 device registered > as %s\n", > > video_device_node_name(&vc- > >vdev)); > > > > -- > Kind regards, > > Sakari Ailus > e-mail: sakari.ailus@iki.fi XMPP: sailus@retiisi.org.uk
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a9d4484..2b4b009 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -36,6 +36,7 @@ #include <linux/firmware.h> #include <linux/kernel.h> #include <linux/mutex.h> +#include <linux/refcount.h> #include <linux/slab.h> #include <linux/videodev2.h> #include <linux/mm.h> @@ -256,7 +257,7 @@ struct s2255_vc { struct s2255_dev { struct s2255_vc vc[MAX_CHANNELS]; struct v4l2_device v4l2_dev; - atomic_t num_channels; + refcount_t num_channels; int frames; struct mutex lock; /* channels[].vdev.lock */ struct mutex cmdlock; /* protects cmdbuf */ @@ -1581,11 +1582,11 @@ static void s2255_video_device_release(struct video_device *vdev) container_of(vdev, struct s2255_vc, vdev); dprintk(dev, 4, "%s, chnls: %d\n", __func__, - atomic_read(&dev->num_channels)); + refcount_read(&dev->num_channels)); v4l2_ctrl_handler_free(&vc->hdl); - if (atomic_dec_and_test(&dev->num_channels)) + if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); return; } @@ -1688,7 +1689,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) "failed to register video device!\n"); break; } - atomic_inc(&dev->num_channels); + refcount_set(&dev->num_channels, 1); v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", video_device_node_name(&vc->vdev)); @@ -1696,11 +1697,11 @@ static int s2255_probe_v4l(struct s2255_dev *dev) pr_info("Sensoray 2255 V4L driver Revision: %s\n", S2255_VERSION); /* if no channels registered, return error and probe will fail*/ - if (atomic_read(&dev->num_channels) == 0) { + if (refcount_read(&dev->num_channels) == 0) { v4l2_device_unregister(&dev->v4l2_dev); return ret; } - if (atomic_read(&dev->num_channels) != MAX_CHANNELS) + if (refcount_read(&dev->num_channels) != MAX_CHANNELS) pr_warn("s2255: Not all channels available.\n"); return 0; } @@ -2248,7 +2249,7 @@ static int s2255_probe(struct usb_interface *interface, goto errorFWDATA1; } - atomic_set(&dev->num_channels, 0); + refcount_set(&dev->num_channels, 0); dev->pid = id->idProduct; dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); if (!dev->fw_data) @@ -2368,12 +2369,12 @@ static void s2255_disconnect(struct usb_interface *interface) { struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); int i; - int channels = atomic_read(&dev->num_channels); + int channels = refcount_read(&dev->num_channels); mutex_lock(&dev->lock); v4l2_device_disconnect(&dev->v4l2_dev); mutex_unlock(&dev->lock); /*see comments in the uvc_driver.c usb disconnect function */ - atomic_inc(&dev->num_channels); + refcount_inc(&dev->num_channels); /* unregister each video device. */ for (i = 0; i < channels; i++) video_unregister_device(&dev->vc[i].vdev); @@ -2386,7 +2387,7 @@ static void s2255_disconnect(struct usb_interface *interface) dev->vc[i].vidstatus_ready = 1; wake_up(&dev->vc[i].wait_vidstatus); } - if (atomic_dec_and_test(&dev->num_channels)) + if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); dev_info(&interface->dev, "%s\n", __func__); }