使用CAP_SYS_ADMIN和CAP_IPC_LOCK功能从bash脚本启动perf

时间:2017-05-15 14:03:34

标签: linux bash perf linux-capabilities

我想利用功能来运行一些带有perf的测试,而无需运行root命令而不调整/proc/sys/kernel/perf_event_paranoid。 perf的一些错误消息说:

You may not have permission to collect stats.
Consider tweaking /proc/sys/kernel/perf_event_paranoid,
which controls use of the performance events system by
unprivileged users (without CAP_SYS_ADMIN).
The current value is 2:
-1: Allow use of (almost) all events by all users
>= 0: Disallow raw tracepoint access by users without CAP_IPC_LOCK
>= 1: Disallow CPU event access by users without CAP_SYS_ADMIN
>= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN

所以我尝试用以下方式创建一些具有相同源但不同功能集的bash脚本:

wrapper_no_cap.sh -> no capabilities set
wrapper_cap_ipc_lock.sh -> setcap cap_ipc_lock+eip ./wrapper_cap_ipc_lock.sh
wrapper_cap_sys_admin.sh -> setcap cap_sys_admin+eip ./wrapper_cap_sys_admin.sh

每个脚本都有相同的来源,如下所示:

#!/bin/bash
perf stat -e L1-dcache-load-misses:k seq 1 10

但我运行的每个脚本都给我结果,好像我是一个普通用户(这意味着我无法计算内核事件或其他特权的东西)。当我调用脚本时,功能会被丢弃。 perf版本为4.11.ga351e9

这种方法有什么问题?

2 个答案:

答案 0 :(得分:0)

脚本文件通常禁用它们的suid位(在内核和某些shell解释器中),似乎对功能有类似的影响(脚本文件实际上是使用git commit等解释器启动的,所以脚本中的功能文件可能不会被进程继承):

使用小的简单编译程序用exec / execve调用perf并在二进制ELF上设置功能。<​​/ p>

Linux内核中用于脚本启动的实际代码 - http://elixir.free-electrons.com/linux/v4.10/source/fs/binfmt_script.c - 使用解释器二进制文件,而不是脚本文件(旧bash ./scriptfile)来获取suid等权限

bprm->file

http://elixir.free-electrons.com/linux/v4.10/source/fs/exec.c#L1512

/*
 * OK, now restart the process with the interpreter's dentry.
 */
file = open_exec(interp);
if (IS_ERR(file))
    return PTR_ERR(file);

bprm->file = file;
retval = prepare_binprm(bprm);

答案 1 :(得分:-1)

我发现了利用@osgx建议的转变。

我写了这个包装perf的小C程序。这是:

#include <unistd.h>
#include <stdio.h>
#include <sys/capability.h>

#define MY_CAPABILIY "cap_sys_admin+eip"

int main(int argc, char * argv[], char * envp[])
{
    cap_t old_cap=cap_get_proc(); //save current capabilities
    //getting MY_CAPABILITY associated struct
    cap_t csa = cap_from_text(MY_CAPABILIY);  
    //set capabilities
    if(cap_set_proc(csa)<0) fprintf(stderr,"cannot set %s\n",MY_CAPABILIY);
    execve("/usr/bin/perf",argv,envp);     //exec perf 
    //restore capabilties
    if(cap_set_proc(old_cap)<0) fprintf(stderr, "Error on capability restore\n" );
    return 0;
}

让我们调用从perf_wrapper上面的代码生成的可执行文件。它使用libcap编译(将选项-lcap添加到gcc)。可执行文件只是将MY_CAPABILITY设置为进程的功能,然后运行perf(或其他命令)。但这不足以使用CAP_SYS_ADMIN运行perf,因为perf的可执行文件没有任何功能。为了让事情有效,还需要为perf可执行文件添加一些功能。

步骤如下:

  1. sudo setcap cap_sys_admin+ei /usr/bin/perf,这将CAP_SYS_ADMIN的perf功能设置为有效且可继承(也允许设置允许普通用户在没有功能的情况下运行perf)。
  2. sudo setcap cap_sys_admin+eip perf_wrapper设置了perf_wrapper
  3. 的功能

    现在可以通过执行perf_wrapper并在正常的bash脚本中像perf一样传递params来使用perf和CAP_SYS_ADMIN。

    注意:我不是能力方面的专家。我希望我没有犯很大的安全错误。