1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2019 SUSE LLC <mdoucha@suse.cz>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * CVE 2018-12896
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Check for possible overflow of posix timer overrun counter. Create
10f08c3bdfSopenharmony_ci * a CLOCK_REALTIME timer, set extremely low timer interval and expiration
11f08c3bdfSopenharmony_ci * value just right to cause overrun overflow into negative values, start
12f08c3bdfSopenharmony_ci * the timer with TIMER_ABSTIME flag to cause overruns immediately. Then just
13f08c3bdfSopenharmony_ci * check the overrun counter in the timer signal handler. On a patched system,
14f08c3bdfSopenharmony_ci * the value returned by timer_getoverrun() should be capped at INT_MAX and
15f08c3bdfSopenharmony_ci * not allowed to overflow into negative range. Bug fixed in:
16f08c3bdfSopenharmony_ci *
17f08c3bdfSopenharmony_ci *  commit 78c9c4dfbf8c04883941445a195276bb4bb92c76
18f08c3bdfSopenharmony_ci *  Author: Thomas Gleixner <tglx@linutronix.de>
19f08c3bdfSopenharmony_ci *  Date:   Tue Jun 26 15:21:32 2018 +0200
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci *  posix-timers: Sanitize overrun handling
22f08c3bdfSopenharmony_ci */
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_ci#include <unistd.h>
25f08c3bdfSopenharmony_ci#include <signal.h>
26f08c3bdfSopenharmony_ci#include <time.h>
27f08c3bdfSopenharmony_ci#include <limits.h>
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci#include "tst_test.h"
30f08c3bdfSopenharmony_ci#include "tst_safe_clocks.h"
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_cistatic timer_t timer;
33f08c3bdfSopenharmony_cistatic volatile int handler_called, overrun, saved_errno;
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_cistatic struct timespec realtime_resolution;
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_cistatic void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
38f08c3bdfSopenharmony_ci{
39f08c3bdfSopenharmony_ci	struct itimerspec spec;
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci	/*
42f08c3bdfSopenharmony_ci	 * Signal handler will be called twice in total because kernel will
43f08c3bdfSopenharmony_ci	 * schedule another pending signal before the timer gets disabled.
44f08c3bdfSopenharmony_ci	 */
45f08c3bdfSopenharmony_ci	if (handler_called)
46f08c3bdfSopenharmony_ci		return;
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ci	errno = 0;
49f08c3bdfSopenharmony_ci	overrun = timer_getoverrun(timer);
50f08c3bdfSopenharmony_ci	saved_errno = errno;
51f08c3bdfSopenharmony_ci	memset(&spec, 0, sizeof(struct itimerspec));
52f08c3bdfSopenharmony_ci	SAFE_TIMER_SETTIME(timer, 0, &spec, NULL);
53f08c3bdfSopenharmony_ci	handler_called = 1;
54f08c3bdfSopenharmony_ci}
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_cistatic void setup(void)
57f08c3bdfSopenharmony_ci{
58f08c3bdfSopenharmony_ci	struct sigevent sev;
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	memset(&sev, 0, sizeof(struct sigevent));
61f08c3bdfSopenharmony_ci	sev.sigev_notify = SIGEV_SIGNAL;
62f08c3bdfSopenharmony_ci	sev.sigev_signo = SIGUSR1;
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	SAFE_SIGNAL(SIGUSR1, sighandler);
65f08c3bdfSopenharmony_ci	SAFE_TIMER_CREATE(CLOCK_REALTIME, &sev, &timer);
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	SAFE_CLOCK_GETRES(CLOCK_REALTIME, &realtime_resolution);
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	tst_res(TINFO, "CLOCK_REALTIME resolution %lins",
70f08c3bdfSopenharmony_ci	        (long)realtime_resolution.tv_nsec);
71f08c3bdfSopenharmony_ci}
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_cistatic void run(void)
74f08c3bdfSopenharmony_ci{
75f08c3bdfSopenharmony_ci	int handler_delay = INT_MAX / 7;
76f08c3bdfSopenharmony_ci	long nsec;
77f08c3bdfSopenharmony_ci	struct itimerspec spec;
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci	handler_called = 0;
80f08c3bdfSopenharmony_ci	memset(&spec, 0, sizeof(struct itimerspec));
81f08c3bdfSopenharmony_ci	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &spec.it_value);
82f08c3bdfSopenharmony_ci	nsec = (handler_delay % 100000000) * 10L;
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	if (nsec > spec.it_value.tv_nsec) {
85f08c3bdfSopenharmony_ci		spec.it_value.tv_sec -= 1;
86f08c3bdfSopenharmony_ci		spec.it_value.tv_nsec += 1000000000;
87f08c3bdfSopenharmony_ci	}
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	/* spec.it_value = now - 1.4 * max overrun value */
90f08c3bdfSopenharmony_ci	/* IOW, overflow will land right in the middle of negative range */
91f08c3bdfSopenharmony_ci	spec.it_value.tv_sec -= (handler_delay / 100000000) * realtime_resolution.tv_nsec;
92f08c3bdfSopenharmony_ci	spec.it_value.tv_nsec -= nsec;
93f08c3bdfSopenharmony_ci	spec.it_interval.tv_nsec = realtime_resolution.tv_nsec;
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	SAFE_TIMER_SETTIME(timer, TIMER_ABSTIME, &spec, NULL);
96f08c3bdfSopenharmony_ci	while (!handler_called);
97f08c3bdfSopenharmony_ci	errno = saved_errno;
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci	if (overrun == -1)
100f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "Error reading timer overrun count");
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci	if (overrun == INT_MAX) {
103f08c3bdfSopenharmony_ci		tst_res(TPASS, "Timer overrun count is capped");
104f08c3bdfSopenharmony_ci		return;
105f08c3bdfSopenharmony_ci	}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci	if (overrun < 0) {
108f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Timer overrun counter overflow");
109f08c3bdfSopenharmony_ci		return;
110f08c3bdfSopenharmony_ci	}
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	tst_res(TFAIL, "Timer overrun counter is wrong: %d; expected %d or "
113f08c3bdfSopenharmony_ci		"negative number", overrun, INT_MAX);
114f08c3bdfSopenharmony_ci}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_cistatic void cleanup(void)
117f08c3bdfSopenharmony_ci{
118f08c3bdfSopenharmony_ci	SAFE_TIMER_DELETE(timer);
119f08c3bdfSopenharmony_ci}
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_cistatic struct tst_test test = {
122f08c3bdfSopenharmony_ci	.test_all = run,
123f08c3bdfSopenharmony_ci	.setup = setup,
124f08c3bdfSopenharmony_ci	.cleanup = cleanup,
125f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
126f08c3bdfSopenharmony_ci		{"linux-git", "78c9c4dfbf8c"},
127f08c3bdfSopenharmony_ci		{"CVE", "2018-12896"},
128f08c3bdfSopenharmony_ci		{}
129f08c3bdfSopenharmony_ci	}
130f08c3bdfSopenharmony_ci};
131