Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: extend usable life of event timestamps to 2106 on 32 bit systems

The input events use struct timeval to store event time, unfortunately
this structure is not y2038 safe and is being replaced in kernel with
y2038 safe structures.

Because of ABI concerns we can not change the size or the layout of
structure input_event, so we opt to re-interpreting the 'seconds' part
of timestamp as an unsigned value, effectively doubling the range of
values, to year 2106.

Newer glibc that has support for 32 bit applications to use 64 bit
time_t supplies __USE_TIME_BITS64 define [1], that we can use to present
the userspace with updated input_event layout. The updated layout will
cause the compile time breakage, alerting applications and distributions
maintainers to the issue. Existing 32 binaries will continue working
without any changes until 2038.

Ultimately userspace applications should switch to using monotonic or
boot time clocks, as realtime clock is not very well suited for input
event timestamps as it can go backwards (see a80b83b7b8 "Input: evdev -
add CLOCK_BOOTTIME support" by by John Stultz). With monotonic clock the
practical range of reported times will always fit into the pair of 32
bit values, as we do not expect any system to stay up for a hundred
years without a single reboot.

[1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign

Suggested-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Patchwork-Id: 10148083
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Deepa Dinamani and committed by
Dmitry Torokhov
152194fe eca3be9b

+32 -14
+13 -7
drivers/input/evdev.c
··· 135 135 continue; 136 136 } else if (head != i) { 137 137 /* move entry to fill the gap */ 138 - client->buffer[head].time = ev->time; 139 - client->buffer[head].type = ev->type; 140 - client->buffer[head].code = ev->code; 141 - client->buffer[head].value = ev->value; 138 + client->buffer[head] = *ev; 142 139 } 143 140 144 141 num++; ··· 154 157 { 155 158 struct input_event ev; 156 159 ktime_t time; 160 + struct timespec64 ts; 157 161 158 162 time = client->clk_type == EV_CLK_REAL ? 159 163 ktime_get_real() : ··· 162 164 ktime_get() : 163 165 ktime_get_boottime(); 164 166 165 - ev.time = ktime_to_timeval(time); 167 + ts = ktime_to_timespec64(time); 168 + ev.input_event_sec = ts.tv_sec; 169 + ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 166 170 ev.type = EV_SYN; 167 171 ev.code = SYN_DROPPED; 168 172 ev.value = 0; ··· 241 241 */ 242 242 client->tail = (client->head - 2) & (client->bufsize - 1); 243 243 244 - client->buffer[client->tail].time = event->time; 244 + client->buffer[client->tail].input_event_sec = 245 + event->input_event_sec; 246 + client->buffer[client->tail].input_event_usec = 247 + event->input_event_usec; 245 248 client->buffer[client->tail].type = EV_SYN; 246 249 client->buffer[client->tail].code = SYN_DROPPED; 247 250 client->buffer[client->tail].value = 0; ··· 265 262 struct evdev *evdev = client->evdev; 266 263 const struct input_value *v; 267 264 struct input_event event; 265 + struct timespec64 ts; 268 266 bool wakeup = false; 269 267 270 268 if (client->revoked) 271 269 return; 272 270 273 - event.time = ktime_to_timeval(ev_time[client->clk_type]); 271 + ts = ktime_to_timespec64(ev_time[client->clk_type]); 272 + event.input_event_sec = ts.tv_sec; 273 + event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 274 274 275 275 /* Interrupts are disabled, just acquire the lock. */ 276 276 spin_lock(&client->buffer_lock);
+4 -4
drivers/input/input-compat.c
··· 24 24 sizeof(struct input_event_compat))) 25 25 return -EFAULT; 26 26 27 - event->time.tv_sec = compat_event.time.tv_sec; 28 - event->time.tv_usec = compat_event.time.tv_usec; 27 + event->input_event_sec = compat_event.sec; 28 + event->input_event_usec = compat_event.usec; 29 29 event->type = compat_event.type; 30 30 event->code = compat_event.code; 31 31 event->value = compat_event.value; ··· 44 44 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { 45 45 struct input_event_compat compat_event; 46 46 47 - compat_event.time.tv_sec = event->time.tv_sec; 48 - compat_event.time.tv_usec = event->time.tv_usec; 47 + compat_event.sec = event->input_event_sec; 48 + compat_event.usec = event->input_event_usec; 49 49 compat_event.type = event->type; 50 50 compat_event.code = event->code; 51 51 compat_event.value = event->value;
+2 -1
drivers/input/input-compat.h
··· 18 18 #ifdef CONFIG_COMPAT 19 19 20 20 struct input_event_compat { 21 - struct compat_timeval time; 21 + compat_ulong_t sec; 22 + compat_ulong_t usec; 22 23 __u16 type; 23 24 __u16 code; 24 25 __s32 value;
+2 -2
drivers/input/misc/uinput.c
··· 90 90 udev->buff[udev->head].code = code; 91 91 udev->buff[udev->head].value = value; 92 92 ktime_get_ts64(&ts); 93 - udev->buff[udev->head].time.tv_sec = ts.tv_sec; 94 - udev->buff[udev->head].time.tv_usec = ts.tv_nsec / NSEC_PER_USEC; 93 + udev->buff[udev->head].input_event_sec = ts.tv_sec; 94 + udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 95 95 udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; 96 96 97 97 wake_up_interruptible(&udev->waitq);
+11
include/uapi/linux/input.h
··· 21 21 22 22 /* 23 23 * The event structure itself 24 + * Note that __USE_TIME_BITS64 is defined by libc based on 25 + * application's request to use 64 bit time_t. 24 26 */ 25 27 26 28 struct input_event { 29 + #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL) 27 30 struct timeval time; 31 + #define input_event_sec time.tv_sec 32 + #define input_event_usec time.tv_usec 33 + #else 34 + __kernel_ulong_t __sec; 35 + __kernel_ulong_t __usec; 36 + #define input_event_sec __sec 37 + #define input_event_usec __usec 38 + #endif 28 39 __u16 type; 29 40 __u16 code; 30 41 __s32 value;