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