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

d_path.c (5367B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define _GNU_SOURCE
      3#include <test_progs.h>
      4#include <sys/stat.h>
      5#include <linux/sched.h>
      6#include <sys/syscall.h>
      7
      8#define MAX_PATH_LEN		128
      9#define MAX_FILES		7
     10
     11#include "test_d_path.skel.h"
     12#include "test_d_path_check_rdonly_mem.skel.h"
     13#include "test_d_path_check_types.skel.h"
     14
     15static int duration;
     16
     17static struct {
     18	__u32 cnt;
     19	char paths[MAX_FILES][MAX_PATH_LEN];
     20} src;
     21
     22static int set_pathname(int fd, pid_t pid)
     23{
     24	char buf[MAX_PATH_LEN];
     25
     26	snprintf(buf, MAX_PATH_LEN, "/proc/%d/fd/%d", pid, fd);
     27	return readlink(buf, src.paths[src.cnt++], MAX_PATH_LEN);
     28}
     29
     30static int trigger_fstat_events(pid_t pid)
     31{
     32	int sockfd = -1, procfd = -1, devfd = -1;
     33	int localfd = -1, indicatorfd = -1;
     34	int pipefd[2] = { -1, -1 };
     35	struct stat fileStat;
     36	int ret = -1;
     37
     38	/* unmountable pseudo-filesystems */
     39	if (CHECK(pipe(pipefd) < 0, "trigger", "pipe failed\n"))
     40		return ret;
     41	/* unmountable pseudo-filesystems */
     42	sockfd = socket(AF_INET, SOCK_STREAM, 0);
     43	if (CHECK(sockfd < 0, "trigger", "socket failed\n"))
     44		goto out_close;
     45	/* mountable pseudo-filesystems */
     46	procfd = open("/proc/self/comm", O_RDONLY);
     47	if (CHECK(procfd < 0, "trigger", "open /proc/self/comm failed\n"))
     48		goto out_close;
     49	devfd = open("/dev/urandom", O_RDONLY);
     50	if (CHECK(devfd < 0, "trigger", "open /dev/urandom failed\n"))
     51		goto out_close;
     52	localfd = open("/tmp/d_path_loadgen.txt", O_CREAT | O_RDONLY, 0644);
     53	if (CHECK(localfd < 0, "trigger", "open /tmp/d_path_loadgen.txt failed\n"))
     54		goto out_close;
     55	/* bpf_d_path will return path with (deleted) */
     56	remove("/tmp/d_path_loadgen.txt");
     57	indicatorfd = open("/tmp/", O_PATH);
     58	if (CHECK(indicatorfd < 0, "trigger", "open /tmp/ failed\n"))
     59		goto out_close;
     60
     61	ret = set_pathname(pipefd[0], pid);
     62	if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[0]\n"))
     63		goto out_close;
     64	ret = set_pathname(pipefd[1], pid);
     65	if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[1]\n"))
     66		goto out_close;
     67	ret = set_pathname(sockfd, pid);
     68	if (CHECK(ret < 0, "trigger", "set_pathname failed for socket\n"))
     69		goto out_close;
     70	ret = set_pathname(procfd, pid);
     71	if (CHECK(ret < 0, "trigger", "set_pathname failed for proc\n"))
     72		goto out_close;
     73	ret = set_pathname(devfd, pid);
     74	if (CHECK(ret < 0, "trigger", "set_pathname failed for dev\n"))
     75		goto out_close;
     76	ret = set_pathname(localfd, pid);
     77	if (CHECK(ret < 0, "trigger", "set_pathname failed for file\n"))
     78		goto out_close;
     79	ret = set_pathname(indicatorfd, pid);
     80	if (CHECK(ret < 0, "trigger", "set_pathname failed for dir\n"))
     81		goto out_close;
     82
     83	/* triggers vfs_getattr */
     84	fstat(pipefd[0], &fileStat);
     85	fstat(pipefd[1], &fileStat);
     86	fstat(sockfd, &fileStat);
     87	fstat(procfd, &fileStat);
     88	fstat(devfd, &fileStat);
     89	fstat(localfd, &fileStat);
     90	fstat(indicatorfd, &fileStat);
     91
     92out_close:
     93	/* triggers filp_close */
     94	close(pipefd[0]);
     95	close(pipefd[1]);
     96	close(sockfd);
     97	close(procfd);
     98	close(devfd);
     99	close(localfd);
    100	close(indicatorfd);
    101	return ret;
    102}
    103
    104static void test_d_path_basic(void)
    105{
    106	struct test_d_path__bss *bss;
    107	struct test_d_path *skel;
    108	int err;
    109
    110	skel = test_d_path__open_and_load();
    111	if (CHECK(!skel, "setup", "d_path skeleton failed\n"))
    112		goto cleanup;
    113
    114	err = test_d_path__attach(skel);
    115	if (CHECK(err, "setup", "attach failed: %d\n", err))
    116		goto cleanup;
    117
    118	bss = skel->bss;
    119	bss->my_pid = getpid();
    120
    121	err = trigger_fstat_events(bss->my_pid);
    122	if (err < 0)
    123		goto cleanup;
    124
    125	if (CHECK(!bss->called_stat,
    126		  "stat",
    127		  "trampoline for security_inode_getattr was not called\n"))
    128		goto cleanup;
    129
    130	if (CHECK(!bss->called_close,
    131		  "close",
    132		  "trampoline for filp_close was not called\n"))
    133		goto cleanup;
    134
    135	for (int i = 0; i < MAX_FILES; i++) {
    136		CHECK(strncmp(src.paths[i], bss->paths_stat[i], MAX_PATH_LEN),
    137		      "check",
    138		      "failed to get stat path[%d]: %s vs %s\n",
    139		      i, src.paths[i], bss->paths_stat[i]);
    140		CHECK(strncmp(src.paths[i], bss->paths_close[i], MAX_PATH_LEN),
    141		      "check",
    142		      "failed to get close path[%d]: %s vs %s\n",
    143		      i, src.paths[i], bss->paths_close[i]);
    144		/* The d_path helper returns size plus NUL char, hence + 1 */
    145		CHECK(bss->rets_stat[i] != strlen(bss->paths_stat[i]) + 1,
    146		      "check",
    147		      "failed to match stat return [%d]: %d vs %zd [%s]\n",
    148		      i, bss->rets_stat[i], strlen(bss->paths_stat[i]) + 1,
    149		      bss->paths_stat[i]);
    150		CHECK(bss->rets_close[i] != strlen(bss->paths_stat[i]) + 1,
    151		      "check",
    152		      "failed to match stat return [%d]: %d vs %zd [%s]\n",
    153		      i, bss->rets_close[i], strlen(bss->paths_close[i]) + 1,
    154		      bss->paths_stat[i]);
    155	}
    156
    157cleanup:
    158	test_d_path__destroy(skel);
    159}
    160
    161static void test_d_path_check_rdonly_mem(void)
    162{
    163	struct test_d_path_check_rdonly_mem *skel;
    164
    165	skel = test_d_path_check_rdonly_mem__open_and_load();
    166	ASSERT_ERR_PTR(skel, "unexpected_load_overwriting_rdonly_mem");
    167
    168	test_d_path_check_rdonly_mem__destroy(skel);
    169}
    170
    171static void test_d_path_check_types(void)
    172{
    173	struct test_d_path_check_types *skel;
    174
    175	skel = test_d_path_check_types__open_and_load();
    176	ASSERT_ERR_PTR(skel, "unexpected_load_passing_wrong_type");
    177
    178	test_d_path_check_types__destroy(skel);
    179}
    180
    181void test_d_path(void)
    182{
    183	if (test__start_subtest("basic"))
    184		test_d_path_basic();
    185
    186	if (test__start_subtest("check_rdonly_mem"))
    187		test_d_path_check_rdonly_mem();
    188
    189	if (test__start_subtest("check_alloc_mem"))
    190		test_d_path_check_types();
    191}