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

cloexec.c (2081B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <errno.h>
      3#include <sched.h>
      4#include "util.h" // for sched_getcpu()
      5#include "../perf-sys.h"
      6#include "cloexec.h"
      7#include "event.h"
      8#include "asm/bug.h"
      9#include "debug.h"
     10#include <unistd.h>
     11#include <sys/syscall.h>
     12#include <linux/string.h>
     13
     14static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
     15
     16int __weak sched_getcpu(void)
     17{
     18#ifdef __NR_getcpu
     19	unsigned cpu;
     20	int err = syscall(__NR_getcpu, &cpu, NULL, NULL);
     21	if (!err)
     22		return cpu;
     23#else
     24	errno = ENOSYS;
     25#endif
     26	return -1;
     27}
     28
     29static int perf_flag_probe(void)
     30{
     31	/* use 'safest' configuration as used in evsel__fallback() */
     32	struct perf_event_attr attr = {
     33		.type = PERF_TYPE_SOFTWARE,
     34		.config = PERF_COUNT_SW_CPU_CLOCK,
     35		.exclude_kernel = 1,
     36	};
     37	int fd;
     38	int err;
     39	int cpu;
     40	pid_t pid = -1;
     41	char sbuf[STRERR_BUFSIZE];
     42
     43	cpu = sched_getcpu();
     44	if (cpu < 0)
     45		cpu = 0;
     46
     47	/*
     48	 * Using -1 for the pid is a workaround to avoid gratuitous jump label
     49	 * changes.
     50	 */
     51	while (1) {
     52		/* check cloexec flag */
     53		fd = sys_perf_event_open(&attr, pid, cpu, -1,
     54					 PERF_FLAG_FD_CLOEXEC);
     55		if (fd < 0 && pid == -1 && errno == EACCES) {
     56			pid = 0;
     57			continue;
     58		}
     59		break;
     60	}
     61	err = errno;
     62
     63	if (fd >= 0) {
     64		close(fd);
     65		return 1;
     66	}
     67
     68	WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES,
     69		  "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
     70		  err, str_error_r(err, sbuf, sizeof(sbuf)));
     71
     72	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
     73	while (1) {
     74		fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
     75		if (fd < 0 && pid == -1 && errno == EACCES) {
     76			pid = 0;
     77			continue;
     78		}
     79		break;
     80	}
     81	err = errno;
     82
     83	if (fd >= 0)
     84		close(fd);
     85
     86	if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES,
     87		      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
     88		      err, str_error_r(err, sbuf, sizeof(sbuf))))
     89		return -1;
     90
     91	return 0;
     92}
     93
     94unsigned long perf_event_open_cloexec_flag(void)
     95{
     96	static bool probed;
     97
     98	if (!probed) {
     99		if (perf_flag_probe() <= 0)
    100			flag = 0;
    101		probed = true;
    102	}
    103
    104	return flag;
    105}