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

procfs.c (3966B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define _GNU_SOURCE
      3#include <errno.h>
      4#include <fcntl.h>
      5#include <math.h>
      6#include <sched.h>
      7#include <stdio.h>
      8#include <stdbool.h>
      9#include <stdlib.h>
     10#include <sys/stat.h>
     11#include <sys/syscall.h>
     12#include <sys/types.h>
     13#include <time.h>
     14#include <unistd.h>
     15
     16#include "log.h"
     17#include "timens.h"
     18
     19/*
     20 * Test shouldn't be run for a day, so add 10 days to child
     21 * time and check parent's time to be in the same day.
     22 */
     23#define MAX_TEST_TIME_SEC		(60*5)
     24#define DAY_IN_SEC			(60*60*24)
     25#define TEN_DAYS_IN_SEC			(10*DAY_IN_SEC)
     26
     27static int child_ns, parent_ns;
     28
     29static int switch_ns(int fd)
     30{
     31	if (setns(fd, CLONE_NEWTIME))
     32		return pr_perror("setns()");
     33
     34	return 0;
     35}
     36
     37static int init_namespaces(void)
     38{
     39	char path[] = "/proc/self/ns/time_for_children";
     40	struct stat st1, st2;
     41
     42	parent_ns = open(path, O_RDONLY);
     43	if (parent_ns <= 0)
     44		return pr_perror("Unable to open %s", path);
     45
     46	if (fstat(parent_ns, &st1))
     47		return pr_perror("Unable to stat the parent timens");
     48
     49	if (unshare_timens())
     50		return -1;
     51
     52	child_ns = open(path, O_RDONLY);
     53	if (child_ns <= 0)
     54		return pr_perror("Unable to open %s", path);
     55
     56	if (fstat(child_ns, &st2))
     57		return pr_perror("Unable to stat the timens");
     58
     59	if (st1.st_ino == st2.st_ino)
     60		return pr_err("The same child_ns after CLONE_NEWTIME");
     61
     62	if (_settime(CLOCK_BOOTTIME, TEN_DAYS_IN_SEC))
     63		return -1;
     64
     65	return 0;
     66}
     67
     68static int read_proc_uptime(struct timespec *uptime)
     69{
     70	unsigned long up_sec, up_nsec;
     71	FILE *proc;
     72
     73	proc = fopen("/proc/uptime", "r");
     74	if (proc == NULL) {
     75		pr_perror("Unable to open /proc/uptime");
     76		return -1;
     77	}
     78
     79	if (fscanf(proc, "%lu.%02lu", &up_sec, &up_nsec) != 2) {
     80		if (errno) {
     81			pr_perror("fscanf");
     82			return -errno;
     83		}
     84		pr_err("failed to parse /proc/uptime");
     85		return -1;
     86	}
     87	fclose(proc);
     88
     89	uptime->tv_sec = up_sec;
     90	uptime->tv_nsec = up_nsec;
     91	return 0;
     92}
     93
     94static int read_proc_stat_btime(unsigned long long *boottime_sec)
     95{
     96	FILE *proc;
     97	char line_buf[2048];
     98
     99	proc = fopen("/proc/stat", "r");
    100	if (proc == NULL) {
    101		pr_perror("Unable to open /proc/stat");
    102		return -1;
    103	}
    104
    105	while (fgets(line_buf, 2048, proc)) {
    106		if (sscanf(line_buf, "btime %llu", boottime_sec) != 1)
    107			continue;
    108		fclose(proc);
    109		return 0;
    110	}
    111	if (errno) {
    112		pr_perror("fscanf");
    113		fclose(proc);
    114		return -errno;
    115	}
    116	pr_err("failed to parse /proc/stat");
    117	fclose(proc);
    118	return -1;
    119}
    120
    121static int check_uptime(void)
    122{
    123	struct timespec uptime_new, uptime_old;
    124	time_t uptime_expected;
    125	double prec = MAX_TEST_TIME_SEC;
    126
    127	if (switch_ns(parent_ns))
    128		return pr_err("switch_ns(%d)", parent_ns);
    129
    130	if (read_proc_uptime(&uptime_old))
    131		return 1;
    132
    133	if (switch_ns(child_ns))
    134		return pr_err("switch_ns(%d)", child_ns);
    135
    136	if (read_proc_uptime(&uptime_new))
    137		return 1;
    138
    139	uptime_expected = uptime_old.tv_sec + TEN_DAYS_IN_SEC;
    140	if (fabs(difftime(uptime_new.tv_sec, uptime_expected)) > prec) {
    141		pr_fail("uptime in /proc/uptime: old %ld, new %ld [%ld]",
    142			uptime_old.tv_sec, uptime_new.tv_sec,
    143			uptime_old.tv_sec + TEN_DAYS_IN_SEC);
    144		return 1;
    145	}
    146
    147	ksft_test_result_pass("Passed for /proc/uptime\n");
    148	return 0;
    149}
    150
    151static int check_stat_btime(void)
    152{
    153	unsigned long long btime_new, btime_old;
    154	unsigned long long btime_expected;
    155
    156	if (switch_ns(parent_ns))
    157		return pr_err("switch_ns(%d)", parent_ns);
    158
    159	if (read_proc_stat_btime(&btime_old))
    160		return 1;
    161
    162	if (switch_ns(child_ns))
    163		return pr_err("switch_ns(%d)", child_ns);
    164
    165	if (read_proc_stat_btime(&btime_new))
    166		return 1;
    167
    168	btime_expected = btime_old - TEN_DAYS_IN_SEC;
    169	if (btime_new != btime_expected) {
    170		pr_fail("btime in /proc/stat: old %llu, new %llu [%llu]",
    171			btime_old, btime_new, btime_expected);
    172		return 1;
    173	}
    174
    175	ksft_test_result_pass("Passed for /proc/stat btime\n");
    176	return 0;
    177}
    178
    179int main(int argc, char *argv[])
    180{
    181	int ret = 0;
    182
    183	nscheck();
    184
    185	ksft_set_plan(2);
    186
    187	if (init_namespaces())
    188		return 1;
    189
    190	ret |= check_uptime();
    191	ret |= check_stat_btime();
    192
    193	if (ret)
    194		ksft_exit_fail();
    195	ksft_exit_pass();
    196	return ret;
    197}