aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepa Dinamani <deepa.kernel@gmail.com>2018-01-07 20:44:42 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2018-01-09 19:40:30 -0500
commit152194fe9c3f03232b9c0d0264793a7fa4af82f8 (patch)
tree2c21b0ba04050b8a86562e55aec816f9ea029c4b
parenteca3be9b95ac7cf9442654a54962859d74f8e38a (diff)
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>
-rw-r--r--drivers/input/evdev.c20
-rw-r--r--drivers/input/input-compat.c8
-rw-r--r--drivers/input/input-compat.h3
-rw-r--r--drivers/input/misc/uinput.c4
-rw-r--r--include/uapi/linux/input.h11
5 files changed, 32 insertions, 14 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 925571475005..116088fc3621 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -135,10 +135,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
135 continue; 135 continue;
136 } else if (head != i) { 136 } else if (head != i) {
137 /* move entry to fill the gap */ 137 /* move entry to fill the gap */
138 client->buffer[head].time = ev->time; 138 client->buffer[head] = *ev;
139 client->buffer[head].type = ev->type;
140 client->buffer[head].code = ev->code;
141 client->buffer[head].value = ev->value;
142 } 139 }
143 140
144 num++; 141 num++;
@@ -157,6 +154,7 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
157{ 154{
158 struct input_event ev; 155 struct input_event ev;
159 ktime_t time; 156 ktime_t time;
157 struct timespec64 ts;
160 158
161 time = client->clk_type == EV_CLK_REAL ? 159 time = client->clk_type == EV_CLK_REAL ?
162 ktime_get_real() : 160 ktime_get_real() :
@@ -164,7 +162,9 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
164 ktime_get() : 162 ktime_get() :
165 ktime_get_boottime(); 163 ktime_get_boottime();
166 164
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;
168 ev.type = EV_SYN; 168 ev.type = EV_SYN;
169 ev.code = SYN_DROPPED; 169 ev.code = SYN_DROPPED;
170 ev.value = 0; 170 ev.value = 0;
@@ -241,7 +241,10 @@ static void __pass_event(struct evdev_client *client,
241 */ 241 */
242 client->tail = (client->head - 2) & (client->bufsize - 1); 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 client->buffer[client->tail].type = EV_SYN; 248 client->buffer[client->tail].type = EV_SYN;
246 client->buffer[client->tail].code = SYN_DROPPED; 249 client->buffer[client->tail].code = SYN_DROPPED;
247 client->buffer[client->tail].value = 0; 250 client->buffer[client->tail].value = 0;
@@ -262,12 +265,15 @@ static void evdev_pass_values(struct evdev_client *client,
262 struct evdev *evdev = client->evdev; 265 struct evdev *evdev = client->evdev;
263 const struct input_value *v; 266 const struct input_value *v;
264 struct input_event event; 267 struct input_event event;
268 struct timespec64 ts;
265 bool wakeup = false; 269 bool wakeup = false;
266 270
267 if (client->revoked) 271 if (client->revoked)
268 return; 272 return;
269 273
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;
271 277
272 /* Interrupts are disabled, just acquire the lock. */ 278 /* Interrupts are disabled, just acquire the lock. */
273 spin_lock(&client->buffer_lock); 279 spin_lock(&client->buffer_lock);
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index 2186f71c9fe5..fda8d6d2a268 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -24,8 +24,8 @@ int input_event_from_user(const char __user *buffer,
24 sizeof(struct input_event_compat))) 24 sizeof(struct input_event_compat)))
25 return -EFAULT; 25 return -EFAULT;
26 26
27 event->time.tv_sec = compat_event.time.tv_sec; 27 event->input_event_sec = compat_event.sec;
28 event->time.tv_usec = compat_event.time.tv_usec; 28 event->input_event_usec = compat_event.usec;
29 event->type = compat_event.type; 29 event->type = compat_event.type;
30 event->code = compat_event.code; 30 event->code = compat_event.code;
31 event->value = compat_event.value; 31 event->value = compat_event.value;
@@ -44,8 +44,8 @@ int input_event_to_user(char __user *buffer,
44 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { 44 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
45 struct input_event_compat compat_event; 45 struct input_event_compat compat_event;
46 46
47 compat_event.time.tv_sec = event->time.tv_sec; 47 compat_event.sec = event->input_event_sec;
48 compat_event.time.tv_usec = event->time.tv_usec; 48 compat_event.usec = event->input_event_usec;
49 compat_event.type = event->type; 49 compat_event.type = event->type;
50 compat_event.code = event->code; 50 compat_event.code = event->code;
51 compat_event.value = event->value; 51 compat_event.value = event->value;
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 1563160a7af3..08cd755e73fd 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -18,7 +18,8 @@
18#ifdef CONFIG_COMPAT 18#ifdef CONFIG_COMPAT
19 19
20struct input_event_compat { 20struct input_event_compat {
21 struct compat_timeval time; 21 compat_ulong_t sec;
22 compat_ulong_t usec;
22 __u16 type; 23 __u16 type;
23 __u16 code; 24 __u16 code;
24 __s32 value; 25 __s32 value;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index d521aecbc078..cb4bdbd3e9e2 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -90,8 +90,8 @@ static int uinput_dev_event(struct input_dev *dev,
90 udev->buff[udev->head].code = code; 90 udev->buff[udev->head].code = code;
91 udev->buff[udev->head].value = value; 91 udev->buff[udev->head].value = value;
92 ktime_get_ts64(&ts); 92 ktime_get_ts64(&ts);
93 udev->buff[udev->head].time.tv_sec = ts.tv_sec; 93 udev->buff[udev->head].input_event_sec = ts.tv_sec;
94 udev->buff[udev->head].time.tv_usec = ts.tv_nsec / NSEC_PER_USEC; 94 udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
95 udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; 95 udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
96 96
97 wake_up_interruptible(&udev->waitq); 97 wake_up_interruptible(&udev->waitq);
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 8c5a0bf6ee35..7288a7c573cc 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -21,10 +21,21 @@
21 21
22/* 22/*
23 * The event structure itself 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
26struct input_event { 28struct input_event {
29#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL)
27 struct timeval time; 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 __u16 type; 39 __u16 type;
29 __u16 code; 40 __u16 code;
30 __s32 value; 41 __s32 value;