[libcamera-devel,v3,07/22] v4l2: v4l2_camera_proxy: Check for null arg values in main ioctl handler

Message ID 20200623190836.53446-8-paul.elder@ideasonboard.com
State Superseded
Headers show
Series
  • Support v4l2-compliance
Related show

Commit Message

Paul Elder June 23, 2020, 7:08 p.m. UTC
The ioctl handlers currently don't check if arg is null, so if it ever
is, it will cause a segfault. Check that arg is null and return -EFAULT
in the main vidioc ioctl handler.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

---
Changes in v3:
- check ioctl rw flags for proper return value error
- cosmetic changes

Changes in v2:
- moved !arg check to main ioctl handler, and added a set of supported
  ioctls
- use !arg instead of arg == nullptr
---
 src/v4l2/v4l2_camera_proxy.cpp | 30 ++++++++++++++++++++++++++++++
 src/v4l2/v4l2_camera_proxy.h   |  3 +++
 2 files changed, 33 insertions(+)

Patch

diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index 7d750c0..b7d3644 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -11,6 +11,7 @@ 
 #include <array>
 #include <errno.h>
 #include <linux/videodev2.h>
+#include <set>
 #include <string.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -527,8 +528,37 @@  int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg)
 	return ret;
 }
 
+const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
+	VIDIOC_QUERYCAP,
+	VIDIOC_ENUM_FMT,
+	VIDIOC_G_FMT,
+	VIDIOC_S_FMT,
+	VIDIOC_TRY_FMT,
+	VIDIOC_REQBUFS,
+	VIDIOC_QUERYBUF,
+	VIDIOC_QBUF,
+	VIDIOC_DQBUF,
+	VIDIOC_STREAMON,
+	VIDIOC_STREAMOFF,
+};
+
 int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *arg)
 {
+	if (!arg && (_IOC_DIR(request) & _IOC_WRITE)) {
+		errno = EFAULT;
+		return -1;
+	}
+
+	if (supportedIoctls_.find(request) == supportedIoctls_.end()) {
+		errno = ENOTTY;
+		return -1;
+	}
+
+	if (!arg && (_IOC_DIR(request) & _IOC_READ)) {
+		errno = EFAULT;
+		return -1;
+	}
+
 	int ret;
 	switch (request) {
 	case VIDIOC_QUERYCAP:
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index 2be46e6..2582eb5 100644
--- a/src/v4l2/v4l2_camera_proxy.h
+++ b/src/v4l2/v4l2_camera_proxy.h
@@ -11,6 +11,7 @@ 
 #include <linux/videodev2.h>
 #include <map>
 #include <memory>
+#include <set>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <vector>
@@ -68,6 +69,8 @@  private:
 	static PixelFormat v4l2ToDrm(uint32_t format);
 	static uint32_t drmToV4L2(const PixelFormat &format);
 
+	static const std::set<unsigned long> supportedIoctls_;
+
 	unsigned int refcount_;
 	unsigned int index_;