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