cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

timens.c (4243B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define _GNU_SOURCE
      3#include <errno.h>
      4#include <fcntl.h>
      5#include <sched.h>
      6#include <stdio.h>
      7#include <stdbool.h>
      8#include <sys/stat.h>
      9#include <sys/syscall.h>
     10#include <sys/types.h>
     11#include <time.h>
     12#include <unistd.h>
     13#include <string.h>
     14
     15#include "log.h"
     16#include "timens.h"
     17
     18/*
     19 * Test shouldn't be run for a day, so add 10 days to child
     20 * time and check parent's time to be in the same day.
     21 */
     22#define DAY_IN_SEC			(60*60*24)
     23#define TEN_DAYS_IN_SEC			(10*DAY_IN_SEC)
     24
     25struct test_clock {
     26	clockid_t id;
     27	char *name;
     28	/*
     29	 * off_id is -1 if a clock has own offset, or it contains an index
     30	 * which contains a right offset of this clock.
     31	 */
     32	int off_id;
     33	time_t offset;
     34};
     35
     36#define ct(clock, off_id)	{ clock, #clock, off_id }
     37static struct test_clock clocks[] = {
     38	ct(CLOCK_BOOTTIME, -1),
     39	ct(CLOCK_BOOTTIME_ALARM, 1),
     40	ct(CLOCK_MONOTONIC, -1),
     41	ct(CLOCK_MONOTONIC_COARSE, 1),
     42	ct(CLOCK_MONOTONIC_RAW, 1),
     43};
     44#undef ct
     45
     46static int child_ns, parent_ns = -1;
     47
     48static int switch_ns(int fd)
     49{
     50	if (setns(fd, CLONE_NEWTIME)) {
     51		pr_perror("setns()");
     52		return -1;
     53	}
     54
     55	return 0;
     56}
     57
     58static int init_namespaces(void)
     59{
     60	char path[] = "/proc/self/ns/time_for_children";
     61	struct stat st1, st2;
     62
     63	if (parent_ns == -1) {
     64		parent_ns = open(path, O_RDONLY);
     65		if (parent_ns <= 0)
     66			return pr_perror("Unable to open %s", path);
     67	}
     68
     69	if (fstat(parent_ns, &st1))
     70		return pr_perror("Unable to stat the parent timens");
     71
     72	if (unshare_timens())
     73		return  -1;
     74
     75	child_ns = open(path, O_RDONLY);
     76	if (child_ns <= 0)
     77		return pr_perror("Unable to open %s", path);
     78
     79	if (fstat(child_ns, &st2))
     80		return pr_perror("Unable to stat the timens");
     81
     82	if (st1.st_ino == st2.st_ino)
     83		return pr_perror("The same child_ns after CLONE_NEWTIME");
     84
     85	return 0;
     86}
     87
     88static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
     89{
     90	struct timespec child_ts_new, parent_ts_old, cur_ts;
     91	char *entry = raw_syscall ? "syscall" : "vdso";
     92	double precision = 0.0;
     93
     94	if (check_skip(clocks[clock_index].id))
     95		return 0;
     96
     97	switch (clocks[clock_index].id) {
     98	case CLOCK_MONOTONIC_COARSE:
     99	case CLOCK_MONOTONIC_RAW:
    100		precision = -2.0;
    101		break;
    102	}
    103
    104	if (switch_ns(parent_ns))
    105		return pr_err("switch_ns(%d)", child_ns);
    106
    107	if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
    108		return -1;
    109
    110	child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
    111	child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;
    112
    113	if (switch_ns(child_ns))
    114		return pr_err("switch_ns(%d)", child_ns);
    115
    116	if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
    117		return -1;
    118
    119	if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) {
    120		ksft_test_result_fail(
    121			"Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
    122			clocks[clock_index].name, entry, parent_ts_old.tv_sec,
    123			child_ts_new.tv_sec, cur_ts.tv_sec);
    124		return -1;
    125	}
    126
    127	if (switch_ns(parent_ns))
    128		return pr_err("switch_ns(%d)", parent_ns);
    129
    130	if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
    131		return -1;
    132
    133	if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) {
    134		ksft_test_result_fail(
    135			"Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
    136			clocks[clock_index].name, entry, parent_ts_old.tv_sec,
    137			child_ts_new.tv_sec, cur_ts.tv_sec);
    138		/* Let's play nice and put it closer to original */
    139		clock_settime(clocks[clock_index].id, &cur_ts);
    140		return -1;
    141	}
    142
    143	ksft_test_result_pass("Passed for %s (%s)\n",
    144				clocks[clock_index].name, entry);
    145	return 0;
    146}
    147
    148int main(int argc, char *argv[])
    149{
    150	unsigned int i;
    151	time_t offset;
    152	int ret = 0;
    153
    154	nscheck();
    155
    156	check_supported_timers();
    157
    158	ksft_set_plan(ARRAY_SIZE(clocks) * 2);
    159
    160	if (init_namespaces())
    161		return 1;
    162
    163	/* Offsets have to be set before tasks enter the namespace. */
    164	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
    165		if (clocks[i].off_id != -1)
    166			continue;
    167		offset = TEN_DAYS_IN_SEC + i * 1000;
    168		clocks[i].offset = offset;
    169		if (_settime(clocks[i].id, offset))
    170			return 1;
    171	}
    172
    173	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
    174		if (clocks[i].off_id != -1)
    175			offset = clocks[clocks[i].off_id].offset;
    176		else
    177			offset = clocks[i].offset;
    178		ret |= test_gettime(i, true, offset);
    179		ret |= test_gettime(i, false, offset);
    180	}
    181
    182	if (ret)
    183		ksft_exit_fail();
    184
    185	ksft_exit_pass();
    186	return !!ret;
    187}