aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-ioctl.c
diff options
context:
space:
mode:
authorTrent Piepho <xyzzy@speakeasy.org>2009-03-03 23:21:02 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:05 -0400
commit19c96e4b7d3c80071982a052e4a921c1a39875d9 (patch)
tree8d255ec32ae288ca568cc1d148d6b7a615f25ed0 /drivers/media/video/v4l2-ioctl.c
parent55d5834d370416946fda7781a5a9ed394a465580 (diff)
V4L/DVB (10811): videodev: only copy needed part of RW ioctl's parameter
There are many RW ioctls() in v4l2 where userspace only supplies one or two of the first fields in the structure passed to the ioctl. The driver then fills in the rest of the fields. Instead of copying the entire structure from userspace to the kernel we only need to copy those fields that userspace is actually supposed to supply. What's more, the fields that are meant to be only be output from the driver can be zeroed out in the videodev code, in case the driver doesn't fill them all in. Many of the ioctl handlers in v4l2_ioctl do this already, but my patch does this at one common point and so all the memsets for each ioctl can be deleted. For VIDIOC_G_SLICED_VBI_CAP, which has one input field ('type') and other output-only fields, the input field is near the end of the structure instead of at the beginning. So there is still a memset in it's ioctl handler to zero out the beginning of the struct. There were a couple mistakes with the existing code: For VIDIOC_G_AUDIO the index field was preserved, but G_AUDIO is a read only ioctl so nothing is copied from userspace to preserve. For VIDIOC_G_FREQUENCY the tuner field was not preserved like it should have been. This would be a problem if there was any hardware with more than one tuner/modulator. For VIDIOC_ENUM_FRAMESIZES and VIDIOC_ENUM_FRAMEINTERVALS, none of the fields were preserved even though each ioctl has several field that are supposed to be inputs to the driver! Obviously these ioctls don't get used much. The index field is needed if the driver has multiple discrete sizes/rates and other fields can be used too, e.g. if the size depends on pixel format or frame rate depends on image size for example. Signed-off-by: Trent Piepho <xyzzy@speakeasy.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-ioctl.c')
-rw-r--r--drivers/media/video/v4l2-ioctl.c107
1 files changed, 52 insertions, 55 deletions
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 175688e9489f..00c0f76b9b5d 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -726,16 +726,8 @@ static long __video_do_ioctl(struct file *file,
726 case VIDIOC_ENUM_FMT: 726 case VIDIOC_ENUM_FMT:
727 { 727 {
728 struct v4l2_fmtdesc *f = arg; 728 struct v4l2_fmtdesc *f = arg;
729 enum v4l2_buf_type type;
730 unsigned int index;
731 729
732 index = f->index; 730 switch (f->type) {
733 type = f->type;
734 memset(f, 0, sizeof(*f));
735 f->index = index;
736 f->type = type;
737
738 switch (type) {
739 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 731 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
740 if (ops->vidioc_enum_fmt_vid_cap) 732 if (ops->vidioc_enum_fmt_vid_cap)
741 ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); 733 ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
@@ -772,8 +764,6 @@ static long __video_do_ioctl(struct file *file,
772 { 764 {
773 struct v4l2_format *f = (struct v4l2_format *)arg; 765 struct v4l2_format *f = (struct v4l2_format *)arg;
774 766
775 memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
776
777 /* FIXME: Should be one dump per type */ 767 /* FIXME: Should be one dump per type */
778 dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); 768 dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
779 769
@@ -969,11 +959,6 @@ static long __video_do_ioctl(struct file *file,
969 if (ret) 959 if (ret)
970 break; 960 break;
971 961
972 /* Zero out all fields starting with bytesysed, which is
973 * everything but index and type. */
974 memset(0, &p->bytesused,
975 sizeof(*p) - offsetof(typeof(*p), bytesused));
976
977 ret = ops->vidioc_querybuf(file, fh, p); 962 ret = ops->vidioc_querybuf(file, fh, p);
978 if (!ret) 963 if (!ret)
979 dbgbuf(cmd, vfd, p); 964 dbgbuf(cmd, vfd, p);
@@ -1159,12 +1144,9 @@ static long __video_do_ioctl(struct file *file,
1159 case VIDIOC_ENUMINPUT: 1144 case VIDIOC_ENUMINPUT:
1160 { 1145 {
1161 struct v4l2_input *p = arg; 1146 struct v4l2_input *p = arg;
1162 int i = p->index;
1163 1147
1164 if (!ops->vidioc_enum_input) 1148 if (!ops->vidioc_enum_input)
1165 break; 1149 break;
1166 memset(p, 0, sizeof(*p));
1167 p->index = i;
1168 1150
1169 ret = ops->vidioc_enum_input(file, fh, p); 1151 ret = ops->vidioc_enum_input(file, fh, p);
1170 if (!ret) 1152 if (!ret)
@@ -1203,12 +1185,9 @@ static long __video_do_ioctl(struct file *file,
1203 case VIDIOC_ENUMOUTPUT: 1185 case VIDIOC_ENUMOUTPUT:
1204 { 1186 {
1205 struct v4l2_output *p = arg; 1187 struct v4l2_output *p = arg;
1206 int i = p->index;
1207 1188
1208 if (!ops->vidioc_enum_output) 1189 if (!ops->vidioc_enum_output)
1209 break; 1190 break;
1210 memset(p, 0, sizeof(*p));
1211 p->index = i;
1212 1191
1213 ret = ops->vidioc_enum_output(file, fh, p); 1192 ret = ops->vidioc_enum_output(file, fh, p);
1214 if (!ret) 1193 if (!ret)
@@ -1384,13 +1363,11 @@ static long __video_do_ioctl(struct file *file,
1384 case VIDIOC_G_AUDIO: 1363 case VIDIOC_G_AUDIO:
1385 { 1364 {
1386 struct v4l2_audio *p = arg; 1365 struct v4l2_audio *p = arg;
1387 __u32 index = p->index;
1388 1366
1389 if (!ops->vidioc_g_audio) 1367 if (!ops->vidioc_g_audio)
1390 break; 1368 break;
1391 1369
1392 memset(p, 0, sizeof(*p)); 1370 memset(p, 0, sizeof(*p));
1393 p->index = index;
1394 ret = ops->vidioc_g_audio(file, fh, p); 1371 ret = ops->vidioc_g_audio(file, fh, p);
1395 if (!ret) 1372 if (!ret)
1396 dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " 1373 dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1485,15 +1462,10 @@ static long __video_do_ioctl(struct file *file,
1485 case VIDIOC_G_CROP: 1462 case VIDIOC_G_CROP:
1486 { 1463 {
1487 struct v4l2_crop *p = arg; 1464 struct v4l2_crop *p = arg;
1488 __u32 type;
1489 1465
1490 if (!ops->vidioc_g_crop) 1466 if (!ops->vidioc_g_crop)
1491 break; 1467 break;
1492 1468
1493 type = p->type;
1494 memset(p, 0, sizeof(*p));
1495 p->type = type;
1496
1497 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); 1469 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
1498 ret = ops->vidioc_g_crop(file, fh, p); 1470 ret = ops->vidioc_g_crop(file, fh, p);
1499 if (!ret) 1471 if (!ret)
@@ -1514,16 +1486,11 @@ static long __video_do_ioctl(struct file *file,
1514 case VIDIOC_CROPCAP: 1486 case VIDIOC_CROPCAP:
1515 { 1487 {
1516 struct v4l2_cropcap *p = arg; 1488 struct v4l2_cropcap *p = arg;
1517 __u32 type;
1518 1489
1519 /*FIXME: Should also show v4l2_fract pixelaspect */ 1490 /*FIXME: Should also show v4l2_fract pixelaspect */
1520 if (!ops->vidioc_cropcap) 1491 if (!ops->vidioc_cropcap)
1521 break; 1492 break;
1522 1493
1523 type = p->type;
1524 memset(p, 0, sizeof(*p));
1525 p->type = type;
1526
1527 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); 1494 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
1528 ret = ops->vidioc_cropcap(file, fh, p); 1495 ret = ops->vidioc_cropcap(file, fh, p);
1529 if (!ret) { 1496 if (!ret) {
@@ -1581,7 +1548,6 @@ static long __video_do_ioctl(struct file *file,
1581 1548
1582 if (!ops->vidioc_encoder_cmd) 1549 if (!ops->vidioc_encoder_cmd)
1583 break; 1550 break;
1584 memset(&p->raw, 0, sizeof(p->raw));
1585 ret = ops->vidioc_encoder_cmd(file, fh, p); 1551 ret = ops->vidioc_encoder_cmd(file, fh, p);
1586 if (!ret) 1552 if (!ret)
1587 dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); 1553 dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1593,7 +1559,6 @@ static long __video_do_ioctl(struct file *file,
1593 1559
1594 if (!ops->vidioc_try_encoder_cmd) 1560 if (!ops->vidioc_try_encoder_cmd)
1595 break; 1561 break;
1596 memset(&p->raw, 0, sizeof(p->raw));
1597 ret = ops->vidioc_try_encoder_cmd(file, fh, p); 1562 ret = ops->vidioc_try_encoder_cmd(file, fh, p);
1598 if (!ret) 1563 if (!ret)
1599 dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); 1564 dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1602,10 +1567,6 @@ static long __video_do_ioctl(struct file *file,
1602 case VIDIOC_G_PARM: 1567 case VIDIOC_G_PARM:
1603 { 1568 {
1604 struct v4l2_streamparm *p = arg; 1569 struct v4l2_streamparm *p = arg;
1605 __u32 type = p->type;
1606
1607 memset(p, 0, sizeof(*p));
1608 p->type = type;
1609 1570
1610 if (ops->vidioc_g_parm) { 1571 if (ops->vidioc_g_parm) {
1611 ret = ops->vidioc_g_parm(file, fh, p); 1572 ret = ops->vidioc_g_parm(file, fh, p);
@@ -1638,14 +1599,10 @@ static long __video_do_ioctl(struct file *file,
1638 case VIDIOC_G_TUNER: 1599 case VIDIOC_G_TUNER:
1639 { 1600 {
1640 struct v4l2_tuner *p = arg; 1601 struct v4l2_tuner *p = arg;
1641 __u32 index = p->index;
1642 1602
1643 if (!ops->vidioc_g_tuner) 1603 if (!ops->vidioc_g_tuner)
1644 break; 1604 break;
1645 1605
1646 memset(p, 0, sizeof(*p));
1647 p->index = index;
1648
1649 ret = ops->vidioc_g_tuner(file, fh, p); 1606 ret = ops->vidioc_g_tuner(file, fh, p);
1650 if (!ret) 1607 if (!ret)
1651 dbgarg(cmd, "index=%d, name=%s, type=%d, " 1608 dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1682,8 +1639,6 @@ static long __video_do_ioctl(struct file *file,
1682 if (!ops->vidioc_g_frequency) 1639 if (!ops->vidioc_g_frequency)
1683 break; 1640 break;
1684 1641
1685 memset(p->reserved, 0, sizeof(p->reserved));
1686
1687 ret = ops->vidioc_g_frequency(file, fh, p); 1642 ret = ops->vidioc_g_frequency(file, fh, p);
1688 if (!ret) 1643 if (!ret)
1689 dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", 1644 dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1704,12 +1659,13 @@ static long __video_do_ioctl(struct file *file,
1704 case VIDIOC_G_SLICED_VBI_CAP: 1659 case VIDIOC_G_SLICED_VBI_CAP:
1705 { 1660 {
1706 struct v4l2_sliced_vbi_cap *p = arg; 1661 struct v4l2_sliced_vbi_cap *p = arg;
1707 __u32 type = p->type;
1708 1662
1709 if (!ops->vidioc_g_sliced_vbi_cap) 1663 if (!ops->vidioc_g_sliced_vbi_cap)
1710 break; 1664 break;
1711 memset(p, 0, sizeof(*p)); 1665
1712 p->type = type; 1666 /* Clear up to type, everything after type is zerod already */
1667 memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
1668
1713 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); 1669 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
1714 ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); 1670 ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
1715 if (!ret) 1671 if (!ret)
@@ -1782,8 +1738,6 @@ static long __video_do_ioctl(struct file *file,
1782 if (!ops->vidioc_enum_framesizes) 1738 if (!ops->vidioc_enum_framesizes)
1783 break; 1739 break;
1784 1740
1785 memset(p, 0, sizeof(*p));
1786
1787 ret = ops->vidioc_enum_framesizes(file, fh, p); 1741 ret = ops->vidioc_enum_framesizes(file, fh, p);
1788 dbgarg(cmd, 1742 dbgarg(cmd,
1789 "index=%d, pixelformat=%d, type=%d ", 1743 "index=%d, pixelformat=%d, type=%d ",
@@ -1815,8 +1769,6 @@ static long __video_do_ioctl(struct file *file,
1815 if (!ops->vidioc_enum_frameintervals) 1769 if (!ops->vidioc_enum_frameintervals)
1816 break; 1770 break;
1817 1771
1818 memset(p, 0, sizeof(*p));
1819
1820 ret = ops->vidioc_enum_frameintervals(file, fh, p); 1772 ret = ops->vidioc_enum_frameintervals(file, fh, p);
1821 dbgarg(cmd, 1773 dbgarg(cmd,
1822 "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", 1774 "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
@@ -1865,6 +1817,44 @@ static long __video_do_ioctl(struct file *file,
1865 return ret; 1817 return ret;
1866} 1818}
1867 1819
1820/* In some cases, only a few fields are used as input, i.e. when the app sets
1821 * "index" and then the driver fills in the rest of the structure for the thing
1822 * with that index. We only need to copy up the first non-input field. */
1823static unsigned long cmd_input_size(unsigned int cmd)
1824{
1825 /* Size of structure up to and including 'field' */
1826#define CMDINSIZE(cmd, type, field) case _IOC_NR(VIDIOC_##cmd): return \
1827 offsetof(struct v4l2_##type, field) + \
1828 sizeof(((struct v4l2_##type *)0)->field);
1829
1830 switch (_IOC_NR(cmd)) {
1831 CMDINSIZE(ENUM_FMT, fmtdesc, type);
1832 CMDINSIZE(G_FMT, format, type);
1833 CMDINSIZE(QUERYBUF, buffer, type);
1834 CMDINSIZE(G_PARM, streamparm, type);
1835 CMDINSIZE(ENUMSTD, standard, index);
1836 CMDINSIZE(ENUMINPUT, input, index);
1837 CMDINSIZE(G_CTRL, control, id);
1838 CMDINSIZE(G_TUNER, tuner, index);
1839 CMDINSIZE(QUERYCTRL, queryctrl, id);
1840 CMDINSIZE(QUERYMENU, querymenu, index);
1841 CMDINSIZE(ENUMOUTPUT, output, index);
1842 CMDINSIZE(G_MODULATOR, modulator, index);
1843 CMDINSIZE(G_FREQUENCY, frequency, tuner);
1844 CMDINSIZE(CROPCAP, cropcap, type);
1845 CMDINSIZE(G_CROP, crop, type);
1846 CMDINSIZE(ENUMAUDIO, audio, index);
1847 CMDINSIZE(ENUMAUDOUT, audioout, index);
1848 CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
1849 CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
1850 CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
1851 CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
1852 CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
1853 default:
1854 return _IOC_SIZE(cmd);
1855 }
1856}
1857
1868long video_ioctl2(struct file *file, 1858long video_ioctl2(struct file *file,
1869 unsigned int cmd, unsigned long arg) 1859 unsigned int cmd, unsigned long arg)
1870{ 1860{
@@ -1901,9 +1891,16 @@ long video_ioctl2(struct file *file,
1901 } 1891 }
1902 1892
1903 err = -EFAULT; 1893 err = -EFAULT;
1904 if (_IOC_DIR(cmd) & _IOC_WRITE) 1894 if (_IOC_DIR(cmd) & _IOC_WRITE) {
1905 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 1895 unsigned long n = cmd_input_size(cmd);
1896
1897 if (copy_from_user(parg, (void __user *)arg, n))
1906 goto out; 1898 goto out;
1899
1900 /* zero out anything we don't copy from userspace */
1901 if (n < _IOC_SIZE(cmd))
1902 memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
1903 }
1907 break; 1904 break;
1908 } 1905 }
1909 1906