如何让dtrace以非根权限运行跟踪的命令?

OS X缺乏linux的strace ,但是它有更好的dtrace

但是,我错过了对单个命令进行简单跟踪的能力。 例如,在linux上,我可以编写strace -f gcc hello.c来引导所有的系统调用,它给了我编译器编译我的程序所需的所有文件名的列表(优秀的memoize脚本是build立在这个技巧之上的)

我想在Mac上移植memo,所以我需要一些strace 。 我真正需要的是gcc读取和写入的文件列表,所以我需要的是更多的truss 。 果然,我可以说dtruss -f gcc hello.c并获得相同的function,但是编译器是以root权限运行的,这显然是不受欢迎的(除了存在巨大的安全风险外,还有一个问题是a.out文件现在由root拥有:-)

然后我尝试了dtruss -f sudo -u myusername gcc hello.c ,但是这样感觉有点不对,而且无论如何也无法正常工作(这时我没有得到a.out文件,不知道为什么)

所有那些长篇故事试图激发我原来的问题: 我如何让dtrace以普通的用户权限运行我的命令,就像strace在linux中一样?

编辑:似乎我不是唯一一个想知道如何做到这一点:问题#1204256是几乎相同,我的(并具有相同的不理想的sudo答案:-)

不是你的问题的答案,但要知道的东西。 OpenSolaris通过“特权”(部分地)解决了这个问题 – 参见这个页面 。 即使在OpenSolaris中,也不可能允许用户没有任何额外的权限来打开自己的进程。 原因是dtrace的工作方式 – 它内核中启用探测。 因此,允许非特权用户探测内核意味着用户可以做很多不必要的事情,例如通过在键盘驱动程序中启用探测器来嗅探其他用户的密码!

最简单的方法是使用sudo:

 sudo dtruss -f sudo -u $USER whoami 

其他解决scheme是先运行debugging器并监视新的特定进程。 例如

 sudo dtruss -fn whoami 

然后在另一个terminal中运行:

 whoami 

就那么简单。

你可以在手册中find更多棘手的论点: man dtruss


或者,您可以附加dtruss到正在运行的用户进程,例如在Mac上:

 sudo dtruss -fp PID 

或者在Linux / Unix上使用strace:

 sudo strace -fp PID 

另一个诡计就是可以执行命令,并在执行之后立即执行该命令。 这里有些例子:

 sudo true; (./Pages &); sudo dtruss -fp `pgrep -n -x Pages` sudo true; (sleep 1 &); sudo dtruss -fp `pgrep -n -x sleep` sudo true; (tail -f /var/log/system.log &); sudo dtruss -fp `pgrep -n -x tail` 

注意:

  • 首先sudo只是在第一次运行时caching密码,

  • 这个技巧对于像ls, date这样的快速命令行不起作用ls, date因为它需要一些时间,直到debugging器将附加到进程,

  • 你必须在两个地方input你的命令,

  • 你可以忽略&运行该过程的背景,如果它已经这样做,

  • 完成debugging后,你将不得不手动杀死后台进程(例如killall -v tail

dtruss-n参数将导致dtruss等待并检查与参数-n匹配的进程。 -f选项仍然可以用于跟踪由-n匹配的进程分叉的进程。

所有这一切意味着,如果您想要为非特权用户build立一个进程(为了争辩,让我们说这是whoami ),请按照下列步骤操作:

  1. 打开一个root shell
  2. 运行dtruss -fn whoami
    • 这将坐等待名为“whoami”的过程存在
  3. 打开一个非特权的shell
  4. 运行whoami
    • 这将正常执行并退出
  5. 在dtruss窗口中观察系统调用轨迹
    • dtruss将不会自行退出 – 它将继续等待匹配的进程 – 所以当你完成后就不要再做了

这个答案重复了@ kenorb的回应的后半部分,但它应该是一个一stream的答案。

我不知道你是否能够像无事生非那样坚强。

一个“sudo [根]的sudo [回到nonroot] cmd”的变种,似乎在一些快速testing中更好地工作是:

 sudo dtruss -f su -l `whoami` cd `pwd` && cmd.... 

外面的sudo当然是如此根源运行。

内在的su回到了我的身边,用-l正确地重新创造了环境,在这一点上,我们需要回到我们开始的地方。

如果你想让环境成为用户通常所获得的东西,我认为“su -l user”比“sudo -u user”要好。 这将是他们的login环境, 我不知道是否有一个让环境inheritance两个用户更改的好方法。

在你的问题中,除了丑陋之外,你还有一个关于“sudo dtruss sudo”解决方法的投诉,就是“我现在没有收到一个.out文件,不知道为什么”。 我不知道为什么,但是在我的小testing脚本中,“sudo dtruss sudo”变体也没有写入testing输出文件,上面的“sudo dtruss su”变体创build了输出文件。

看来,OS X不支持使用dtrace来复制你需要的strace的所有function。 不过,我build议尝试围绕适当的系统调用创build一个包装。 它看起来像DYLD_INSERT_LIBRARIES是你想要破解的环境variables。 这与Linux的LD_PRELOAD基本相同。

执行库函数覆盖的一个更简单的方法是使用DYLD_INSERT_LIBRARIES环境variables(类似于Linux上的LD_PRELOAD)。 这个概念很简单:在加载时,dynamic链接器(dyld)将在加载可执行文件之前加载DYLD_INSERT_LIBRARIES中指定的任何dynamic库。 通过命名与库函数中的函数相同的函数,它将覆盖对原始函数的任何调用。

原始函数也被加载,并且可以使用dlsym(RTLD_NEXT,“function_name”)来检索; function。 这允许一个简单的方法来包装现有的库函数。

根据Tom Robinson的例子 ,您可能也需要设置DYLD_FORCE_FLAT_NAMESPACE=1

仅覆盖fopen的原始示例( lib_overrides.c )的副本:

 #include <stdio.h> #include <unistd.h> #include <dlfcn.h> // for caching the original fopen implementation FILE * (*original_fopen) (const char *, const char *) = NULL; // our fopen override implmentation FILE * fopen(const char * filename, const char * mode) { // if we haven't already, retrieve the original fopen implementation if (!original_fopen) original_fopen = dlsym(RTLD_NEXT, "fopen"); // do our own processing; in this case just print the parameters printf("== fopen: {%s,%s} ==\n", filename, mode); // call the original fopen with the same arugments FILE* f = original_fopen(filename, mode); // return the result return f; } 

用法:

 $ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c $ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib command-to-test 

免责声明:这是来自@ kenorb的答案 。 但它有一些优点:PID比execname更具体。 我们可以在DTrace开始之前做一个短暂的进程。

这有点种族条件,但…

比方说,我们想跟踪cat /etc/hosts

 sudo true && \ (sleep 1; cat /etc/hosts) &; \ sudo dtrace -n 'syscall:::entry /pid == $1/ {@[probefunc] = count();}' $!; \ kill $! 

我们使用sudo true来确保我们在开始运行任何时间敏感之前清除sudo的密码提示。

我们开始一个后台进程(“等待1秒,然后做一些有趣的事情”)。 同时,我们启动DTrace。 我们已经将后台进程的PID捕获到$! ,所以我们可以将它作为arg传递给DTrace。

kill $! 在closuresDTrace后运行。 我们的例子(进程自己closures)没有必要,但它可以帮助我们结束像ping这样的长时间运行的后台进程。 传递-p $! 到DTrace是这样做的首选方式,但在macOS上显然需要一个代码签名的可执行文件。


你可以做的另一件事是在一个单独的shell中运行该命令,并侦听该shell。 看到我的答案 。

我不知道如何以普通用户的方式运行你想要的东西,因为使用dtrace的dtruss似乎需要su权限。

但是,我相信你正在寻找的命令,而不是

dtruss -f sudo -u myusername gcc hello.c

sudo dtruss -f gcc hello.c

input密码后,dtruss将运行dtrace将sudo权限,并且将获得跟踪以及a.out文件。

对不起,我不能有进一步的帮助。