media: v4l2-core: fix v4l2_buffer handling for time64 ABI
authorArnd Bergmann <arnd@arndb.de>
Mon, 16 Dec 2019 14:15:04 +0000 (15:15 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Fri, 3 Jan 2020 14:50:21 +0000 (15:50 +0100)
The v4l2_buffer structure contains a 'struct timeval' member that is
defined by the user space C library, creating an ABI incompatibility
when that gets updated to a 64-bit time_t.

As in v4l2_event, handle this with a special case in video_put_user()
and video_get_user() to replace the memcpy there.

Since the structure also contains a pointer, there are now two
native versions (on 32-bit systems) as well as two compat versions
(on 64-bit systems), which unfortunately complicates the compat
handler quite a bit.

Duplicating the existing handlers for the new types is a safe
conversion for now, but unfortunately this may turn into a
maintenance burden later. A larger-scale rework of the
compat code might be a better alternative, but is out of scope
of the y2038 work.

Sparc64 needs a special case because of their special suseconds_t
definition.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/v4l2-core/v4l2-ioctl.c
include/media/v4l2-ioctl.h
include/uapi/linux/videodev2.h

index f13b232..15035cb 100644 (file)
@@ -474,10 +474,10 @@ static void v4l_print_buffer(const void *arg, bool write_only)
        const struct v4l2_plane *plane;
        int i;
 
-       pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
-                       p->timestamp.tv_sec / 3600,
-                       (int)(p->timestamp.tv_sec / 60) % 60,
-                       (int)(p->timestamp.tv_sec % 60),
+       pr_cont("%02d:%02d:%02d.%09ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
+                       (int)p->timestamp.tv_sec / 3600,
+                       ((int)p->timestamp.tv_sec / 60) % 60,
+                       ((int)p->timestamp.tv_sec % 60),
                        (long)p->timestamp.tv_usec,
                        p->index,
                        prt_names(p->type, v4l2_type_names), p->request_fd,
@@ -3029,6 +3029,14 @@ static unsigned int video_translate_cmd(unsigned int cmd)
 #ifdef CONFIG_COMPAT_32BIT_TIME
        case VIDIOC_DQEVENT_TIME32:
                return VIDIOC_DQEVENT;
+       case VIDIOC_QUERYBUF_TIME32:
+               return VIDIOC_QUERYBUF;
+       case VIDIOC_QBUF_TIME32:
+               return VIDIOC_QBUF;
+       case VIDIOC_DQBUF_TIME32:
+               return VIDIOC_DQBUF;
+       case VIDIOC_PREPARE_BUF_TIME32:
+               return VIDIOC_PREPARE_BUF;
 #endif
        }
 
@@ -3047,6 +3055,39 @@ static int video_get_user(void __user *arg, void *parg, unsigned int cmd,
        }
 
        switch (cmd) {
+#ifdef CONFIG_COMPAT_32BIT_TIME
+       case VIDIOC_QUERYBUF_TIME32:
+       case VIDIOC_QBUF_TIME32:
+       case VIDIOC_DQBUF_TIME32:
+       case VIDIOC_PREPARE_BUF_TIME32: {
+               struct v4l2_buffer_time32 vb32;
+               struct v4l2_buffer *vb = parg;
+
+               if (copy_from_user(&vb32, arg, sizeof(vb32)))
+                       return -EFAULT;
+
+               *vb = (struct v4l2_buffer) {
+                       .index          = vb32.index,
+                       .type           = vb32.type,
+                       .bytesused      = vb32.bytesused,
+                       .flags          = vb32.flags,
+                       .field          = vb32.field,
+                       .timestamp.tv_sec       = vb32.timestamp.tv_sec,
+                       .timestamp.tv_usec      = vb32.timestamp.tv_usec,
+                       .timecode       = vb32.timecode,
+                       .sequence       = vb32.sequence,
+                       .memory         = vb32.memory,
+                       .m.userptr      = vb32.m.userptr,
+                       .length         = vb32.length,
+                       .request_fd     = vb32.request_fd,
+               };
+
+               if (cmd == VIDIOC_QUERYBUF_TIME32)
+                       vb->request_fd = 0;
+
+               break;
+       }
+#endif
        default:
                /*
                 * In some cases, only a few fields are used as input,
@@ -3100,6 +3141,31 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
                        return -EFAULT;
                break;
        }
+       case VIDIOC_QUERYBUF_TIME32:
+       case VIDIOC_QBUF_TIME32:
+       case VIDIOC_DQBUF_TIME32:
+       case VIDIOC_PREPARE_BUF_TIME32: {
+               struct v4l2_buffer *vb = parg;
+               struct v4l2_buffer_time32 vb32 = {
+                       .index          = vb->index,
+                       .type           = vb->type,
+                       .bytesused      = vb->bytesused,
+                       .flags          = vb->flags,
+                       .field          = vb->field,
+                       .timestamp.tv_sec       = vb->timestamp.tv_sec,
+                       .timestamp.tv_usec      = vb->timestamp.tv_usec,
+                       .timecode       = vb->timecode,
+                       .sequence       = vb->sequence,
+                       .memory         = vb->memory,
+                       .m.userptr      = vb->m.userptr,
+                       .length         = vb->length,
+                       .request_fd     = vb->request_fd,
+               };
+
+               if (copy_to_user(arg, &vb32, sizeof(vb32)))
+                       return -EFAULT;
+               break;
+       }
 #endif
        default:
                /*  Copy results into user buffer  */
index 05c1ec9..86878fb 100644 (file)
@@ -749,4 +749,34 @@ struct v4l2_event_time32 {
 
 #define        VIDIOC_DQEVENT_TIME32    _IOR('V', 89, struct v4l2_event_time32)
 
+struct v4l2_buffer_time32 {
+       __u32                   index;
+       __u32                   type;
+       __u32                   bytesused;
+       __u32                   flags;
+       __u32                   field;
+       struct old_timeval32    timestamp;
+       struct v4l2_timecode    timecode;
+       __u32                   sequence;
+
+       /* memory location */
+       __u32                   memory;
+       union {
+               __u32           offset;
+               unsigned long   userptr;
+               struct v4l2_plane *planes;
+               __s32           fd;
+       } m;
+       __u32                   length;
+       __u32                   reserved2;
+       union {
+               __s32           request_fd;
+               __u32           reserved;
+       };
+};
+#define VIDIOC_QUERYBUF_TIME32 _IOWR('V',  9, struct v4l2_buffer_time32)
+#define VIDIOC_QBUF_TIME32     _IOWR('V', 15, struct v4l2_buffer_time32)
+#define VIDIOC_DQBUF_TIME32    _IOWR('V', 17, struct v4l2_buffer_time32)
+#define VIDIOC_PREPARE_BUF_TIME32 _IOWR('V', 93, struct v4l2_buffer_time32)
+
 #endif /* _V4L2_IOCTL_H */
index caf156d..5f9357d 100644 (file)
@@ -912,6 +912,25 @@ struct v4l2_jpegcompression {
 /*
  *     M E M O R Y - M A P P I N G   B U F F E R S
  */
+
+#ifdef __KERNEL__
+/*
+ * This corresponds to the user space version of timeval
+ * for 64-bit time_t. sparc64 is different from everyone
+ * else, using the microseconds in the wrong half of the
+ * second 64-bit word.
+ */
+struct __kernel_v4l2_timeval {
+       long long       tv_sec;
+#if defined(__sparc__) && defined(__arch64__)
+       int             tv_usec;
+       int             __pad;
+#else
+       long long       tv_usec;
+#endif
+};
+#endif
+
 struct v4l2_requestbuffers {
        __u32                   count;
        __u32                   type;           /* enum v4l2_buf_type */
@@ -997,7 +1016,11 @@ struct v4l2_buffer {
        __u32                   bytesused;
        __u32                   flags;
        __u32                   field;
+#ifdef __KERNEL__
+       struct __kernel_v4l2_timeval timestamp;
+#else
        struct timeval          timestamp;
+#endif
        struct v4l2_timecode    timecode;
        __u32                   sequence;