1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2020 SUSE LLC <mdoucha@suse.cz> 4 * 5 * CVE-2017-10661 6 * 7 * Test for race condition vulnerability in timerfd_settime(). Multiple 8 * concurrent calls of timerfd_settime() clearing the CANCEL_ON_SET flag may 9 * cause memory corruption. Fixed in: 10 * 11 * commit 1e38da300e1e395a15048b0af1e5305bd91402f6 12 * Author: Thomas Gleixner <tglx@linutronix.de> 13 * Date: Tue Jan 31 15:24:03 2017 +0100 14 * 15 * timerfd: Protect the might cancel mechanism proper 16 */ 17#include <unistd.h> 18#include "time64_variants.h" 19#include "tst_timer.h" 20#include "tst_safe_timerfd.h" 21#include "tst_fuzzy_sync.h" 22 23#define TIMERFD_FLAGS "timerfd_settime(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)" 24 25#ifndef TFD_TIMER_CANCEL_ON_SET 26#define TFD_TIMER_CANCEL_ON_SET (1<<1) 27#endif 28 29static int fd = -1; 30static struct tst_its its; 31static struct tst_fzsync_pair fzsync_pair; 32 33static struct time64_variants variants[] = { 34#if (__NR_timerfd_settime != __LTP__NR_INVALID_SYSCALL) 35 { .tfd_settime = sys_timerfd_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 36#endif 37 38#if (__NR_timerfd_settime64 != __LTP__NR_INVALID_SYSCALL) 39 { .tfd_settime = sys_timerfd_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 40#endif 41}; 42 43static void setup(void) 44{ 45 struct time64_variants *tv = &variants[tst_variant]; 46 47 tst_res(TINFO, "Testing variant: %s", tv->desc); 48 its.type = tv->ts_type; 49 50 fd = SAFE_TIMERFD_CREATE(CLOCK_REALTIME, 0); 51 52 fzsync_pair.exec_loops = 1000000; 53 tst_fzsync_pair_init(&fzsync_pair); 54} 55 56static void cleanup(void) 57{ 58 if (fd >= 0) 59 SAFE_CLOSE(fd); 60 tst_fzsync_pair_cleanup(&fzsync_pair); 61} 62 63static int punch_clock(int flags) 64{ 65 return variants[tst_variant].tfd_settime(fd, flags, tst_its_get(&its), 66 NULL); 67 68} 69 70static void *thread_run(void *arg) 71{ 72 while (tst_fzsync_run_b(&fzsync_pair)) { 73 tst_fzsync_start_race_b(&fzsync_pair); 74 punch_clock(0); 75 tst_fzsync_end_race_b(&fzsync_pair); 76 } 77 78 return arg; 79} 80 81static void run(void) 82{ 83 tst_fzsync_pair_reset(&fzsync_pair, thread_run); 84 85 while (tst_fzsync_run_a(&fzsync_pair)) { 86 TEST(punch_clock(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)); 87 88 if (TST_RET == -1) 89 tst_brk(TBROK | TTERRNO, TIMERFD_FLAGS " failed"); 90 91 if (TST_RET != 0) 92 tst_brk(TBROK | TTERRNO, "Invalid " TIMERFD_FLAGS 93 " return value"); 94 95 tst_fzsync_start_race_a(&fzsync_pair); 96 punch_clock(0); 97 tst_fzsync_end_race_a(&fzsync_pair); 98 99 if (tst_taint_check()) { 100 tst_res(TFAIL, "Kernel is vulnerable"); 101 return; 102 } 103 } 104 105 tst_res(TPASS, "Nothing bad happened, probably"); 106} 107 108static struct tst_test test = { 109 .test_all = run, 110 .test_variants = ARRAY_SIZE(variants), 111 .setup = setup, 112 .cleanup = cleanup, 113 .taint_check = TST_TAINT_W | TST_TAINT_D, 114 .max_runtime = 150, 115 .tags = (const struct tst_tag[]) { 116 {"linux-git", "1e38da300e1e"}, 117 {"CVE", "2017-10661"}, 118 {} 119 } 120}; 121