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

fs.c (10487B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <ctype.h>
      3#include <errno.h>
      4#include <limits.h>
      5#include <stdbool.h>
      6#include <stdio.h>
      7#include <stdlib.h>
      8#include <string.h>
      9#include <sys/vfs.h>
     10#include <sys/types.h>
     11#include <sys/stat.h>
     12#include <fcntl.h>
     13#include <unistd.h>
     14#include <sys/mount.h>
     15
     16#include "fs.h"
     17#include "debug-internal.h"
     18
     19#define _STR(x) #x
     20#define STR(x) _STR(x)
     21
     22#ifndef SYSFS_MAGIC
     23#define SYSFS_MAGIC            0x62656572
     24#endif
     25
     26#ifndef PROC_SUPER_MAGIC
     27#define PROC_SUPER_MAGIC       0x9fa0
     28#endif
     29
     30#ifndef DEBUGFS_MAGIC
     31#define DEBUGFS_MAGIC          0x64626720
     32#endif
     33
     34#ifndef TRACEFS_MAGIC
     35#define TRACEFS_MAGIC          0x74726163
     36#endif
     37
     38#ifndef HUGETLBFS_MAGIC
     39#define HUGETLBFS_MAGIC        0x958458f6
     40#endif
     41
     42#ifndef BPF_FS_MAGIC
     43#define BPF_FS_MAGIC           0xcafe4a11
     44#endif
     45
     46static const char * const sysfs__fs_known_mountpoints[] = {
     47	"/sys",
     48	0,
     49};
     50
     51static const char * const procfs__known_mountpoints[] = {
     52	"/proc",
     53	0,
     54};
     55
     56#ifndef DEBUGFS_DEFAULT_PATH
     57#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
     58#endif
     59
     60static const char * const debugfs__known_mountpoints[] = {
     61	DEBUGFS_DEFAULT_PATH,
     62	"/debug",
     63	0,
     64};
     65
     66
     67#ifndef TRACEFS_DEFAULT_PATH
     68#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
     69#endif
     70
     71static const char * const tracefs__known_mountpoints[] = {
     72	TRACEFS_DEFAULT_PATH,
     73	"/sys/kernel/debug/tracing",
     74	"/tracing",
     75	"/trace",
     76	0,
     77};
     78
     79static const char * const hugetlbfs__known_mountpoints[] = {
     80	0,
     81};
     82
     83static const char * const bpf_fs__known_mountpoints[] = {
     84	"/sys/fs/bpf",
     85	0,
     86};
     87
     88struct fs {
     89	const char		*name;
     90	const char * const	*mounts;
     91	char			 path[PATH_MAX];
     92	bool			 found;
     93	bool			 checked;
     94	long			 magic;
     95};
     96
     97enum {
     98	FS__SYSFS   = 0,
     99	FS__PROCFS  = 1,
    100	FS__DEBUGFS = 2,
    101	FS__TRACEFS = 3,
    102	FS__HUGETLBFS = 4,
    103	FS__BPF_FS = 5,
    104};
    105
    106#ifndef TRACEFS_MAGIC
    107#define TRACEFS_MAGIC 0x74726163
    108#endif
    109
    110static struct fs fs__entries[] = {
    111	[FS__SYSFS] = {
    112		.name	= "sysfs",
    113		.mounts	= sysfs__fs_known_mountpoints,
    114		.magic	= SYSFS_MAGIC,
    115		.checked = false,
    116	},
    117	[FS__PROCFS] = {
    118		.name	= "proc",
    119		.mounts	= procfs__known_mountpoints,
    120		.magic	= PROC_SUPER_MAGIC,
    121		.checked = false,
    122	},
    123	[FS__DEBUGFS] = {
    124		.name	= "debugfs",
    125		.mounts	= debugfs__known_mountpoints,
    126		.magic	= DEBUGFS_MAGIC,
    127		.checked = false,
    128	},
    129	[FS__TRACEFS] = {
    130		.name	= "tracefs",
    131		.mounts	= tracefs__known_mountpoints,
    132		.magic	= TRACEFS_MAGIC,
    133		.checked = false,
    134	},
    135	[FS__HUGETLBFS] = {
    136		.name	= "hugetlbfs",
    137		.mounts = hugetlbfs__known_mountpoints,
    138		.magic	= HUGETLBFS_MAGIC,
    139		.checked = false,
    140	},
    141	[FS__BPF_FS] = {
    142		.name	= "bpf",
    143		.mounts = bpf_fs__known_mountpoints,
    144		.magic	= BPF_FS_MAGIC,
    145		.checked = false,
    146	},
    147};
    148
    149static bool fs__read_mounts(struct fs *fs)
    150{
    151	bool found = false;
    152	char type[100];
    153	FILE *fp;
    154
    155	fp = fopen("/proc/mounts", "r");
    156	if (fp == NULL)
    157		return NULL;
    158
    159	while (!found &&
    160	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
    161		      fs->path, type) == 2) {
    162
    163		if (strcmp(type, fs->name) == 0)
    164			found = true;
    165	}
    166
    167	fclose(fp);
    168	fs->checked = true;
    169	return fs->found = found;
    170}
    171
    172static int fs__valid_mount(const char *fs, long magic)
    173{
    174	struct statfs st_fs;
    175
    176	if (statfs(fs, &st_fs) < 0)
    177		return -ENOENT;
    178	else if ((long)st_fs.f_type != magic)
    179		return -ENOENT;
    180
    181	return 0;
    182}
    183
    184static bool fs__check_mounts(struct fs *fs)
    185{
    186	const char * const *ptr;
    187
    188	ptr = fs->mounts;
    189	while (*ptr) {
    190		if (fs__valid_mount(*ptr, fs->magic) == 0) {
    191			fs->found = true;
    192			strcpy(fs->path, *ptr);
    193			return true;
    194		}
    195		ptr++;
    196	}
    197
    198	return false;
    199}
    200
    201static void mem_toupper(char *f, size_t len)
    202{
    203	while (len) {
    204		*f = toupper(*f);
    205		f++;
    206		len--;
    207	}
    208}
    209
    210/*
    211 * Check for "NAME_PATH" environment variable to override fs location (for
    212 * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
    213 * for SYSFS_PATH.
    214 */
    215static bool fs__env_override(struct fs *fs)
    216{
    217	char *override_path;
    218	size_t name_len = strlen(fs->name);
    219	/* name + "_PATH" + '\0' */
    220	char upper_name[name_len + 5 + 1];
    221
    222	memcpy(upper_name, fs->name, name_len);
    223	mem_toupper(upper_name, name_len);
    224	strcpy(&upper_name[name_len], "_PATH");
    225
    226	override_path = getenv(upper_name);
    227	if (!override_path)
    228		return false;
    229
    230	fs->found = true;
    231	fs->checked = true;
    232	strncpy(fs->path, override_path, sizeof(fs->path) - 1);
    233	fs->path[sizeof(fs->path) - 1] = '\0';
    234	return true;
    235}
    236
    237static const char *fs__get_mountpoint(struct fs *fs)
    238{
    239	if (fs__env_override(fs))
    240		return fs->path;
    241
    242	if (fs__check_mounts(fs))
    243		return fs->path;
    244
    245	if (fs__read_mounts(fs))
    246		return fs->path;
    247
    248	return NULL;
    249}
    250
    251static const char *fs__mountpoint(int idx)
    252{
    253	struct fs *fs = &fs__entries[idx];
    254
    255	if (fs->found)
    256		return (const char *)fs->path;
    257
    258	/* the mount point was already checked for the mount point
    259	 * but and did not exist, so return NULL to avoid scanning again.
    260	 * This makes the found and not found paths cost equivalent
    261	 * in case of multiple calls.
    262	 */
    263	if (fs->checked)
    264		return NULL;
    265
    266	return fs__get_mountpoint(fs);
    267}
    268
    269static const char *mount_overload(struct fs *fs)
    270{
    271	size_t name_len = strlen(fs->name);
    272	/* "PERF_" + name + "_ENVIRONMENT" + '\0' */
    273	char upper_name[5 + name_len + 12 + 1];
    274
    275	snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
    276	mem_toupper(upper_name, name_len);
    277
    278	return getenv(upper_name) ?: *fs->mounts;
    279}
    280
    281static const char *fs__mount(int idx)
    282{
    283	struct fs *fs = &fs__entries[idx];
    284	const char *mountpoint;
    285
    286	if (fs__mountpoint(idx))
    287		return (const char *)fs->path;
    288
    289	mountpoint = mount_overload(fs);
    290
    291	if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
    292		return NULL;
    293
    294	return fs__check_mounts(fs) ? fs->path : NULL;
    295}
    296
    297#define FS(name, idx)				\
    298const char *name##__mountpoint(void)		\
    299{						\
    300	return fs__mountpoint(idx);		\
    301}						\
    302						\
    303const char *name##__mount(void)			\
    304{						\
    305	return fs__mount(idx);			\
    306}						\
    307						\
    308bool name##__configured(void)			\
    309{						\
    310	return name##__mountpoint() != NULL;	\
    311}
    312
    313FS(sysfs,   FS__SYSFS);
    314FS(procfs,  FS__PROCFS);
    315FS(debugfs, FS__DEBUGFS);
    316FS(tracefs, FS__TRACEFS);
    317FS(hugetlbfs, FS__HUGETLBFS);
    318FS(bpf_fs, FS__BPF_FS);
    319
    320int filename__read_int(const char *filename, int *value)
    321{
    322	char line[64];
    323	int fd = open(filename, O_RDONLY), err = -1;
    324
    325	if (fd < 0)
    326		return -1;
    327
    328	if (read(fd, line, sizeof(line)) > 0) {
    329		*value = atoi(line);
    330		err = 0;
    331	}
    332
    333	close(fd);
    334	return err;
    335}
    336
    337static int filename__read_ull_base(const char *filename,
    338				   unsigned long long *value, int base)
    339{
    340	char line[64];
    341	int fd = open(filename, O_RDONLY), err = -1;
    342
    343	if (fd < 0)
    344		return -1;
    345
    346	if (read(fd, line, sizeof(line)) > 0) {
    347		*value = strtoull(line, NULL, base);
    348		if (*value != ULLONG_MAX)
    349			err = 0;
    350	}
    351
    352	close(fd);
    353	return err;
    354}
    355
    356/*
    357 * Parses @value out of @filename with strtoull.
    358 * By using 16 for base to treat the number as hex.
    359 */
    360int filename__read_xll(const char *filename, unsigned long long *value)
    361{
    362	return filename__read_ull_base(filename, value, 16);
    363}
    364
    365/*
    366 * Parses @value out of @filename with strtoull.
    367 * By using 0 for base, the strtoull detects the
    368 * base automatically (see man strtoull).
    369 */
    370int filename__read_ull(const char *filename, unsigned long long *value)
    371{
    372	return filename__read_ull_base(filename, value, 0);
    373}
    374
    375#define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
    376
    377int filename__read_str(const char *filename, char **buf, size_t *sizep)
    378{
    379	size_t size = 0, alloc_size = 0;
    380	void *bf = NULL, *nbf;
    381	int fd, n, err = 0;
    382	char sbuf[STRERR_BUFSIZE];
    383
    384	fd = open(filename, O_RDONLY);
    385	if (fd < 0)
    386		return -errno;
    387
    388	do {
    389		if (size == alloc_size) {
    390			alloc_size += BUFSIZ;
    391			nbf = realloc(bf, alloc_size);
    392			if (!nbf) {
    393				err = -ENOMEM;
    394				break;
    395			}
    396
    397			bf = nbf;
    398		}
    399
    400		n = read(fd, bf + size, alloc_size - size);
    401		if (n < 0) {
    402			if (size) {
    403				pr_warn("read failed %d: %s\n", errno,
    404					strerror_r(errno, sbuf, sizeof(sbuf)));
    405				err = 0;
    406			} else
    407				err = -errno;
    408
    409			break;
    410		}
    411
    412		size += n;
    413	} while (n > 0);
    414
    415	if (!err) {
    416		*sizep = size;
    417		*buf   = bf;
    418	} else
    419		free(bf);
    420
    421	close(fd);
    422	return err;
    423}
    424
    425int filename__write_int(const char *filename, int value)
    426{
    427	int fd = open(filename, O_WRONLY), err = -1;
    428	char buf[64];
    429
    430	if (fd < 0)
    431		return err;
    432
    433	sprintf(buf, "%d", value);
    434	if (write(fd, buf, sizeof(buf)) == sizeof(buf))
    435		err = 0;
    436
    437	close(fd);
    438	return err;
    439}
    440
    441int procfs__read_str(const char *entry, char **buf, size_t *sizep)
    442{
    443	char path[PATH_MAX];
    444	const char *procfs = procfs__mountpoint();
    445
    446	if (!procfs)
    447		return -1;
    448
    449	snprintf(path, sizeof(path), "%s/%s", procfs, entry);
    450
    451	return filename__read_str(path, buf, sizep);
    452}
    453
    454static int sysfs__read_ull_base(const char *entry,
    455				unsigned long long *value, int base)
    456{
    457	char path[PATH_MAX];
    458	const char *sysfs = sysfs__mountpoint();
    459
    460	if (!sysfs)
    461		return -1;
    462
    463	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
    464
    465	return filename__read_ull_base(path, value, base);
    466}
    467
    468int sysfs__read_xll(const char *entry, unsigned long long *value)
    469{
    470	return sysfs__read_ull_base(entry, value, 16);
    471}
    472
    473int sysfs__read_ull(const char *entry, unsigned long long *value)
    474{
    475	return sysfs__read_ull_base(entry, value, 0);
    476}
    477
    478int sysfs__read_int(const char *entry, int *value)
    479{
    480	char path[PATH_MAX];
    481	const char *sysfs = sysfs__mountpoint();
    482
    483	if (!sysfs)
    484		return -1;
    485
    486	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
    487
    488	return filename__read_int(path, value);
    489}
    490
    491int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
    492{
    493	char path[PATH_MAX];
    494	const char *sysfs = sysfs__mountpoint();
    495
    496	if (!sysfs)
    497		return -1;
    498
    499	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
    500
    501	return filename__read_str(path, buf, sizep);
    502}
    503
    504int sysfs__read_bool(const char *entry, bool *value)
    505{
    506	char *buf;
    507	size_t size;
    508	int ret;
    509
    510	ret = sysfs__read_str(entry, &buf, &size);
    511	if (ret < 0)
    512		return ret;
    513
    514	switch (buf[0]) {
    515	case '1':
    516	case 'y':
    517	case 'Y':
    518		*value = true;
    519		break;
    520	case '0':
    521	case 'n':
    522	case 'N':
    523		*value = false;
    524		break;
    525	default:
    526		ret = -1;
    527	}
    528
    529	free(buf);
    530
    531	return ret;
    532}
    533int sysctl__read_int(const char *sysctl, int *value)
    534{
    535	char path[PATH_MAX];
    536	const char *procfs = procfs__mountpoint();
    537
    538	if (!procfs)
    539		return -1;
    540
    541	snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
    542
    543	return filename__read_int(path, value);
    544}
    545
    546int sysfs__write_int(const char *entry, int value)
    547{
    548	char path[PATH_MAX];
    549	const char *sysfs = sysfs__mountpoint();
    550
    551	if (!sysfs)
    552		return -1;
    553
    554	if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
    555		return -1;
    556
    557	return filename__write_int(path, value);
    558}