Permission denied on perf_event_open, is there another way than to use sudo or changing the perf_event_paranoid file?

Viewed 1266

The only information I could find about the topic is this link:perf_event_open always returns -1, which propose to configure with CONFIG_HW_PERF_EVENTS from what I understood, but I still get the same problem.

I'm implementing a program inspired by the man page of perf_event_open:

static long
       perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                       int cpu, int group_fd, unsigned long flags)
       {
           int ret;

           ret= syscall(__NR_perf_event_open, hw_event, pid, cpu,
                          group_fd, flags);
           return ret;
       }
struct perf_event_attr pe;

int pid = fork();

if (pid > 0 ) {

memset(&pe, 0, sizeof(pe));
           pe.type = PERF_TYPE_HARDWARE;
           pe.size = sizeof(pe);
           pe.config = PERF_COUNT_HW_CPU_CYCLES;
           pe.disabled = 0;
           pe.exclude_kernel = 0;
           pe.exclude_hv = 0;   
            
           fd = perf_event_open(&pe, pid, -1, -1, 0);
if (fd == -1) {
               perror(0);
              exit(EXIT_FAILURE);
           }
}

I always get a -1 return for fd and perror indicates that permission is denied.

Of course I can work around the problem using sudo, but is there another way to allow permission to execute perf_event_open?

PS: I don't want to change the perf_event_paranoid file, which makes the program work when set at -1; I assume it will be at 2.

1 Answers

The RETURN VALUE section of the Linux perf_event_open() system call states in part:

   ...

   EACCES Returned when the requested event requires CAP_PERFMON
          (since Linux 5.8) or CAP_SYS_ADMIN permissions (or a more
          permissive perf_event paranoid setting).  Some common
          cases where an unprivileged process may encounter this
          error: attaching to a process owned by a different user;
          monitoring all processes on a given CPU (i.e., specifying
          the pid argument as -1); and not setting exclude_kernel
          when the paranoid setting requires it.

   ...

   EPERM  Returned on many (but not all) architectures when an
          unsupported exclude_hv, exclude_idle, exclude_user, or
          exclude_kernel setting is specified.

          It can also happen, as with EACCES, when the requested
          event requires CAP_PERFMON (since Linux 5.8) or
          CAP_SYS_ADMIN permissions (or a more permissive perf_event
          paranoid setting).  This includes setting a breakpoint on
          a kernel address, and (since Linux 3.13) setting a kernel
          function-trace tracepoint.

From the example code posted, the values pe.exclude_kernel = 0; or pe.exclude_hv = 0; are likely causing permission issues given your statement about the paranoid setting.

Related