如何让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
),请按照下列步骤操作:
- 打开一个root shell
- 运行
dtruss -fn whoami
- 这将坐等待名为“whoami”的过程存在
- 打开一个非特权的shell
- 运行
whoami
- 这将正常执行并退出
- 在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文件。
对不起,我不能有进一步的帮助。