From 6f0dd24a084a17f9984dd49dffbf7055bf123993 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 10 Jun 2016 14:37:23 -0300 Subject: [media] media: fix media devnode ioctl/syscall and unregister race Media devnode open/ioctl could be in progress when media device unregister is initiated. System calls and ioctls check media device registered status at the beginning, however, there is a window where unregister could be in progress without changing the media devnode status to unregistered. process 1 process 2 fd = open(/dev/media0) media_devnode_is_registered() (returns true here) media_device_unregister() (unregister is in progress and devnode isn't unregistered yet) ... ioctl(fd, ...) __media_ioctl() media_devnode_is_registered() (returns true here) ... media_devnode_unregister() ... (driver releases the media device memory) media_device_ioctl() (By this point devnode->media_dev does not point to allocated memory. use-after free in in mutex_lock_nested) BUG: KASAN: use-after-free in mutex_lock_nested+0x79c/0x800 at addr ffff8801ebe914f0 Fix it by clearing register bit when unregister starts to avoid the race. process 1 process 2 fd = open(/dev/media0) media_devnode_is_registered() (could return true here) media_device_unregister() (clear the register bit, then start unregister.) ... ioctl(fd, ...) __media_ioctl() media_devnode_is_registered() (return false here, ioctl returns I/O error, and will not access media device memory) ... media_devnode_unregister() ... (driver releases the media device memory) Signed-off-by: Shuah Khan Suggested-by: Sakari Ailus Reported-by: Mauro Carvalho Chehab Tested-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/media-devnode.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index 5bb3b0e86d73..f0b7dd79fb92 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -125,6 +125,19 @@ int __must_check media_devnode_register(struct media_device *mdev, struct media_devnode *devnode, struct module *owner); +/** + * media_devnode_unregister_prepare - clear the media device node register bit + * @devnode: the device node to prepare for unregister + * + * This clears the passed device register bit. Future open calls will be met + * with errors. Should be called before media_devnode_unregister() to avoid + * races with unregister and device file open calls. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +void media_devnode_unregister_prepare(struct media_devnode *devnode); + /** * media_devnode_unregister - unregister a media device node * @devnode: the device node to unregister @@ -132,8 +145,7 @@ int __must_check media_devnode_register(struct media_device *mdev, * This unregisters the passed device. Future open calls will be met with * errors. * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. + * Should be called after media_devnode_unregister_prepare() */ void media_devnode_unregister(struct media_devnode *devnode); -- cgit v1.2.3-59-g8ed1b