On 11/26/19 3:43 PM, Arnd Bergmann wrote: > 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. I agree. Hmm, can't you do .u = ev->u ? Or is that not allowed by this syntax? > > Any other ideas? Let me know if I should do a memset() > plus individual member copy instead. I think we have to, unless you have a better solution. This is leaking information from the holes in the struct. >>> + 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 > Regards, Hans