On Mon, Nov 25, 2019 at 3:40 PM Hans Verkuil <hverkuil@xxxxxxxxx> wrote: > On 11/11/19 9:38 PM, Arnd Bergmann wrote: > > switch (cmd) { > > +#ifdef CONFIG_COMPAT_32BIT_TIME > > + case VIDIOC_DQEVENT_TIME32: { > > + struct v4l2_event_time32 ev32; > > + struct v4l2_event *ev = parg; > > + > > + memcpy(&ev32, ev, offsetof(struct v4l2_event, timestamp)); > > + ev32.timestamp.tv_sec = ev->timestamp.tv_sec; > > + ev32.timestamp.tv_nsec = ev->timestamp.tv_nsec; > > + memcpy(&ev32.id, &ev->id, sizeof(*ev) - offsetof(struct v4l2_event, id)); > > This looks dangerous: due to 64-bit alignment requirements the > v4l2_event struct may end with a 4-byte hole at the end of the struct, > which you do not want to copy to ev32. > > I think it is safer to just copy id and reserved separately: > > ev32.id = ev->id; > memcpy(ev32.reserved, ev->reserved, sizeof(ev->reserved)); Actually I think it's that's also bad: The padding in *ev must already be cleared here (otherwise there is a leak of stack data in the kernel already), so *not* copying the padding requires at least adding a memset upfront. I would do the per-member copy like I did for v4l2_buffer in my other reply: struct v4l2_event *ev = parg; struct v4l2_event_time32 ev32 = { .type = ev->type, .pending = ev->pending, .sequence = ev->sequence, .timestamp.tv_sec = ev->timestamp.tv_sec, .timestamp.tv_nsec = ev->timestamp.tv_nsec, .id = ev->id, }; memcpy(ev32.u, ev->u, sizeof(ev->u)); memcpy(ev32.reserved, ev->reserved, sizeof(ev->reserved)); if (copy_to_user(arg, &ev32, sizeof(ev32))) return -EFAULT; Unfortunately this is a little uglier because it still requires the two memcpy() for the arrays, but I think it's good enough. Any other ideas? Let me know if I should do a memset() plus individual member copy instead. > > + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) > > + return -ENOIOCTLCMD; > > + > > + rval = v4l2_event_dequeue(vfh, &ev, file->f_flags & O_NONBLOCK); > > + > > + memcpy(ev32, &ev, offsetof(struct v4l2_event, timestamp)); > > + ev32->timestamp.tv_sec = ev.timestamp.tv_sec; > > + ev32->timestamp.tv_nsec = ev.timestamp.tv_nsec; > > + memcpy(&ev32->id, &ev.id, > > + sizeof(ev) - offsetof(struct v4l2_event, id)); > > Ditto. Using the corresponding code here as well. > > + > > #define V4L2_EVENT_SUB_FL_SEND_INITIAL (1 << 0) > > #define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK (1 << 1) > > > > @@ -2486,6 +2515,7 @@ struct v4l2_create_buffers { > > #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) > > #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) > > #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) > > +#define VIDIOC_DQEVENT_TIME32 _IOR('V', 89, struct v4l2_event_time32) > > Shouldn't this be under #ifdef __KERNEL__? > > And should this be in the public header at all? media/v4l2-ioctl.h might be a better > place. Done. Arnd