diff options
Diffstat (limited to 'drivers/media/media-device.c')
| -rw-r--r-- | drivers/media/media-device.c | 126 |
1 files changed, 106 insertions, 20 deletions
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 6f9eb94e85b..88b97c9e64a 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -20,10 +20,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <linux/types.h> +#include <linux/compat.h> +#include <linux/export.h> #include <linux/ioctl.h> #include <linux/media.h> -#include <linux/export.h> +#include <linux/types.h> #include <media/media-device.h> #include <media/media-devnode.h> @@ -59,7 +60,9 @@ static int media_device_get_info(struct media_device *dev, info.hw_revision = dev->hw_revision; info.driver_version = dev->driver_version; - return copy_to_user(__info, &info, sizeof(*__info)); + if (copy_to_user(__info, &info, sizeof(*__info))) + return -EFAULT; + return 0; } static struct media_entity *find_entity(struct media_device *mdev, u32 id) @@ -90,6 +93,7 @@ static long media_device_enum_entities(struct media_device *mdev, struct media_entity *ent; struct media_entity_desc u_ent; + memset(&u_ent, 0, sizeof(u_ent)); if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) return -EFAULT; @@ -99,9 +103,12 @@ static long media_device_enum_entities(struct media_device *mdev, return -EINVAL; u_ent.id = ent->id; - u_ent.name[0] = '\0'; - if (ent->name) - strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); + if (ent->name) { + strncpy(u_ent.name, ent->name, sizeof(u_ent.name)); + u_ent.name[sizeof(u_ent.name) - 1] = '\0'; + } else { + memset(u_ent.name, 0, sizeof(u_ent.name)); + } u_ent.type = ent->type; u_ent.revision = ent->revision; u_ent.flags = ent->flags; @@ -122,41 +129,40 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, upad->flags = kpad->flags; } -static long media_device_enum_links(struct media_device *mdev, - struct media_links_enum __user *ulinks) +static long __media_device_enum_links(struct media_device *mdev, + struct media_links_enum *links) { struct media_entity *entity; - struct media_links_enum links; - - if (copy_from_user(&links, ulinks, sizeof(links))) - return -EFAULT; - entity = find_entity(mdev, links.entity); + entity = find_entity(mdev, links->entity); if (entity == NULL) return -EINVAL; - if (links.pads) { + if (links->pads) { unsigned int p; for (p = 0; p < entity->num_pads; p++) { struct media_pad_desc pad; + + memset(&pad, 0, sizeof(pad)); media_device_kpad_to_upad(&entity->pads[p], &pad); - if (copy_to_user(&links.pads[p], &pad, sizeof(pad))) + if (copy_to_user(&links->pads[p], &pad, sizeof(pad))) return -EFAULT; } } - if (links.links) { + if (links->links) { struct media_link_desc __user *ulink; unsigned int l; - for (l = 0, ulink = links.links; l < entity->num_links; l++) { + for (l = 0, ulink = links->links; l < entity->num_links; l++) { struct media_link_desc link; /* Ignore backlinks. */ if (entity->links[l].source->entity != entity) continue; + memset(&link, 0, sizeof(link)); media_device_kpad_to_upad(entity->links[l].source, &link.source); media_device_kpad_to_upad(entity->links[l].sink, @@ -167,8 +173,26 @@ static long media_device_enum_links(struct media_device *mdev, ulink++; } } + + return 0; +} + +static long media_device_enum_links(struct media_device *mdev, + struct media_links_enum __user *ulinks) +{ + struct media_links_enum links; + int rval; + + if (copy_from_user(&links, ulinks, sizeof(links))) + return -EFAULT; + + rval = __media_device_enum_links(mdev, &links); + if (rval < 0) + return rval; + if (copy_to_user(ulinks, &links, sizeof(*ulinks))) return -EFAULT; + return 0; } @@ -249,10 +273,71 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, return ret; } +#ifdef CONFIG_COMPAT + +struct media_links_enum32 { + __u32 entity; + compat_uptr_t pads; /* struct media_pad_desc * */ + compat_uptr_t links; /* struct media_link_desc * */ + __u32 reserved[4]; +}; + +static long media_device_enum_links32(struct media_device *mdev, + struct media_links_enum32 __user *ulinks) +{ + struct media_links_enum links; + compat_uptr_t pads_ptr, links_ptr; + + memset(&links, 0, sizeof(links)); + + if (get_user(links.entity, &ulinks->entity) + || get_user(pads_ptr, &ulinks->pads) + || get_user(links_ptr, &ulinks->links)) + return -EFAULT; + + links.pads = compat_ptr(pads_ptr); + links.links = compat_ptr(links_ptr); + + return __media_device_enum_links(mdev, &links); +} + +#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) + +static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *dev = to_media_device(devnode); + long ret; + + switch (cmd) { + case MEDIA_IOC_DEVICE_INFO: + case MEDIA_IOC_ENUM_ENTITIES: + case MEDIA_IOC_SETUP_LINK: + return media_device_ioctl(filp, cmd, arg); + + case MEDIA_IOC_ENUM_LINKS32: + mutex_lock(&dev->graph_mutex); + ret = media_device_enum_links32(dev, + (struct media_links_enum32 __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} +#endif /* CONFIG_COMPAT */ + static const struct media_file_operations media_device_fops = { .owner = THIS_MODULE, .open = media_device_open, .ioctl = media_device_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_device_compat_ioctl, +#endif /* CONFIG_COMPAT */ .release = media_device_close, }; @@ -288,7 +373,8 @@ static void media_device_release(struct media_devnode *mdev) * - dev must point to the parent device * - model must be filled with the device model name */ -int __must_check media_device_register(struct media_device *mdev) +int __must_check __media_device_register(struct media_device *mdev, + struct module *owner) { int ret; @@ -304,7 +390,7 @@ int __must_check media_device_register(struct media_device *mdev) mdev->devnode.fops = &media_device_fops; mdev->devnode.parent = mdev->dev; mdev->devnode.release = media_device_release; - ret = media_devnode_register(&mdev->devnode); + ret = media_devnode_register(&mdev->devnode, owner); if (ret < 0) return ret; @@ -316,7 +402,7 @@ int __must_check media_device_register(struct media_device *mdev) return 0; } -EXPORT_SYMBOL_GPL(media_device_register); +EXPORT_SYMBOL_GPL(__media_device_register); /** * media_device_unregister - unregister a media device |
