]> err.no Git - linux-2.6/commitdiff
V4L/DVB (4154): Fix use-after-free bug in cpia2 driver
authorJesper Juhl <jesper.juhl@gmail.com>
Fri, 23 Jun 2006 16:27:36 +0000 (13:27 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 25 Jun 2006 05:05:14 +0000 (02:05 -0300)
The coverity checker detected a use-after-free error in
drivers/media/video/cpia2/cpia2_v4l.c::cpia2_close() (coverity
error #1281).
What happens is that we lock cam->busy_lock, then proceed to free
resources, and in the case of (--cam->open_count == 0) we finish off by
doing a kfree(cam) and then at the end of the function we do a
mutex_unlock(&cam->busy_lock) which will explode since it'll dereference
the free'd `cam' :
...
mutex_lock(&cam->busy_lock);
...
if (--cam->open_count == 0) {
    ...
    if (!cam->present) {
        video_unregister_device(dev);
        kfree(cam);
    }
}
mutex_unlock(&cam->busy_lock);   <--- PROBLEM, cam no longer around.
...
Since this only happens in the case of open_count going down to zero I
don't see a problem with just releasing the mutex after unregistering the
device and just before the kfree().  In this case there is nothing around
that we can race against; we are in the release method, open_count is zero,
(!cam->present) and the device has just been unregistered, so letting go of
the mutex at this point looks safe to me.
Patch below to implement that solution.
Acked-by: Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/cpia2/cpia2_v4l.c

index 28d93c595df035315608c8a4ba5f70d01349478f..d129db57fcd4bab57861528b200092326bf86bc4 100644 (file)
@@ -343,7 +343,9 @@ static int cpia2_close(struct inode *inode, struct file *file)
                cpia2_free_buffers(cam);
                if (!cam->present) {
                        video_unregister_device(dev);
+                       mutex_unlock(&cam->busy_lock);
                        kfree(cam);
+                       return 0;
                }
        }