media: radio-raremono: change devm_k*alloc to k*alloc [Linux 4.14.136]

This Linux kernel change "media: radio-raremono: change devm_k*alloc to k*alloc" is included in the Linux 4.14.136 release. This change is authored by Luke Nowakowski-Krijger <lnowakow [at] eng.ucsd.edu> on Fri Jun 21 21:04:38 2019 -0400. The commit for this change in Linux stable tree is c4c213d (patch) which is from upstream commit c666355. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream c666355.

media: radio-raremono: change devm_k*alloc to k*alloc

commit c666355e60ddb4748ead3bdd983e3f7f2224aaf0 upstream.

Change devm_k*alloc to k*alloc to manually allocate memory

The manual allocation and freeing of memory is necessary because when
the USB radio is disconnected, the memory associated with devm_k*alloc
is freed. Meaning if we still have unresolved references to the radio
device, then we get use-after-free errors.

This patch fixes this by manually allocating memory, and freeing it in
the v4l2.release callback that gets called when the last radio device
exits.

Reported-and-tested-by: syzbot+a4387f5b6b799f6becbf@syzkaller.appspotmail.com

Signed-off-by: Luke Nowakowski-Krijger <lnowakow@eng.ucsd.edu>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil-cisco@xs4all.nl: cleaned up two small checkpatch.pl warnings]
[hverkuil-cisco@xs4all.nl: prefix subject with driver name]
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 30 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/media/radio/radio-raremono.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 3c0a22a..932c32e 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -283,6 +283,14 @@ static int vidioc_g_frequency(struct file *file, void *priv,
    return 0;
 }

+static void raremono_device_release(struct v4l2_device *v4l2_dev)
+{
+   struct raremono_device *radio = to_raremono_dev(v4l2_dev);
+
+   kfree(radio->buffer);
+   kfree(radio);
+}
+
 /* File system interface */
 static const struct v4l2_file_operations usb_raremono_fops = {
    .owner      = THIS_MODULE,
@@ -307,12 +315,14 @@ static int usb_raremono_probe(struct usb_interface *intf,
    struct raremono_device *radio;
    int retval = 0;

-   radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL);
-   if (radio)
-       radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL);
-
-   if (!radio || !radio->buffer)
+   radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+   if (!radio)
+       return -ENOMEM;
+   radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+   if (!radio->buffer) {
+       kfree(radio);
        return -ENOMEM;
+   }

    radio->usbdev = interface_to_usbdev(intf);
    radio->intf = intf;
@@ -336,7 +346,8 @@ static int usb_raremono_probe(struct usb_interface *intf,
    if (retval != 3 ||
        (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) {
        dev_info(&intf->dev, "this is not Thanko's Raremono.\n");
-       return -ENODEV;
+       retval = -ENODEV;
+       goto free_mem;
    }

    dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n",
@@ -345,7 +356,7 @@ static int usb_raremono_probe(struct usb_interface *intf,
    retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
    if (retval < 0) {
        dev_err(&intf->dev, "couldn't register v4l2_device\n");
-       return retval;
+       goto free_mem;
    }

    mutex_init(&radio->lock);
@@ -357,6 +368,7 @@ static int usb_raremono_probe(struct usb_interface *intf,
    radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops;
    radio->vdev.lock = &radio->lock;
    radio->vdev.release = video_device_release_empty;
+   radio->v4l2_dev.release = raremono_device_release;

    usb_set_intfdata(intf, &radio->v4l2_dev);

@@ -372,6 +384,10 @@ static int usb_raremono_probe(struct usb_interface *intf,
    }
    dev_err(&intf->dev, "could not register video device\n");
    v4l2_device_unregister(&radio->v4l2_dev);
+
+free_mem:
+   kfree(radio->buffer);
+   kfree(radio);
    return retval;
 }

Leave a Reply

Your email address will not be published. Required fields are marked *