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