Skip to content

Commit 152194f

Browse files
deepa-hubdtor
authored andcommitted
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 a80b83b "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 <[email protected]> Signed-off-by: Deepa Dinamani <[email protected]> Acked-by: Peter Hutterer <[email protected]> Patchwork-Id: 10148083 Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent eca3be9 commit 152194f

File tree

5 files changed

+32
-14
lines changed

5 files changed

+32
-14
lines changed

drivers/input/evdev.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
135135
continue;
136136
} else if (head != i) {
137137
/* 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;
142139
}
143140

144141
num++;
@@ -157,14 +154,17 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
157154
{
158155
struct input_event ev;
159156
ktime_t time;
157+
struct timespec64 ts;
160158

161159
time = client->clk_type == EV_CLK_REAL ?
162160
ktime_get_real() :
163161
client->clk_type == EV_CLK_MONO ?
164162
ktime_get() :
165163
ktime_get_boottime();
166164

167-
ev.time = ktime_to_timeval(time);
165+
ts = ktime_to_timespec64(time);
166+
ev.input_event_sec = ts.tv_sec;
167+
ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
168168
ev.type = EV_SYN;
169169
ev.code = SYN_DROPPED;
170170
ev.value = 0;
@@ -241,7 +241,10 @@ static void __pass_event(struct evdev_client *client,
241241
*/
242242
client->tail = (client->head - 2) & (client->bufsize - 1);
243243

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;
245248
client->buffer[client->tail].type = EV_SYN;
246249
client->buffer[client->tail].code = SYN_DROPPED;
247250
client->buffer[client->tail].value = 0;
@@ -262,12 +265,15 @@ static void evdev_pass_values(struct evdev_client *client,
262265
struct evdev *evdev = client->evdev;
263266
const struct input_value *v;
264267
struct input_event event;
268+
struct timespec64 ts;
265269
bool wakeup = false;
266270

267271
if (client->revoked)
268272
return;
269273

270-
event.time = ktime_to_timeval(ev_time[client->clk_type]);
274+
ts = ktime_to_timespec64(ev_time[client->clk_type]);
275+
event.input_event_sec = ts.tv_sec;
276+
event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
271277

272278
/* Interrupts are disabled, just acquire the lock. */
273279
spin_lock(&client->buffer_lock);

drivers/input/input-compat.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ int input_event_from_user(const char __user *buffer,
2424
sizeof(struct input_event_compat)))
2525
return -EFAULT;
2626

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;
2929
event->type = compat_event.type;
3030
event->code = compat_event.code;
3131
event->value = compat_event.value;
@@ -44,8 +44,8 @@ int input_event_to_user(char __user *buffer,
4444
if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
4545
struct input_event_compat compat_event;
4646

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;
4949
compat_event.type = event->type;
5050
compat_event.code = event->code;
5151
compat_event.value = event->value;

drivers/input/input-compat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
#ifdef CONFIG_COMPAT
1919

2020
struct input_event_compat {
21-
struct compat_timeval time;
21+
compat_ulong_t sec;
22+
compat_ulong_t usec;
2223
__u16 type;
2324
__u16 code;
2425
__s32 value;

drivers/input/misc/uinput.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ static int uinput_dev_event(struct input_dev *dev,
9090
udev->buff[udev->head].code = code;
9191
udev->buff[udev->head].value = value;
9292
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;
9595
udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
9696

9797
wake_up_interruptible(&udev->waitq);

include/uapi/linux/input.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,21 @@
2121

2222
/*
2323
* 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.
2426
*/
2527

2628
struct input_event {
29+
#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL)
2730
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
2839
__u16 type;
2940
__u16 code;
3041
__s32 value;

0 commit comments

Comments
 (0)