如何使用非root权限运行trace命令?

时间:2010-06-09 16:36:26

标签: macos root dtrace strace

OS X缺少linux的strace,但它有dtrace,应该会好得多。

但是,我错过了对单个命令进行简单跟踪的功能。例如,在linux上我可以编写strace -f gcc hello.c来限制所有系统调用,这为我提供了编译程序所需的文件名 all 的列表(优秀的memoize }脚本建立在这个技巧上)

我想在mac上移植memoize,所以我需要某种strace。我真正需要的是文件列表gcc读取和写入,所以我需要的更多是truss。我当然可以说dtruss -f gcc hello.c并获得一些相同的功能,但随后编译器运行root权限,这显然是不可取的(除了大量的安全风险,一个问题是a.out文件现在由root拥有: - )

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

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

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

7 个答案:

答案 0 :(得分:43)

最简单的方法是使用sudo:

sudo dtruss -f sudo -u $USER whoami

其他解决方案是首先运行调试器并监视新的特定进程。 E.g。

sudo dtruss -fn whoami

然后在另一个终端中运行:

whoami

这很简单。

您可以在手册中找到更棘手的参数:man dtruss


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

sudo dtruss -fp PID
在Linux / Unix上使用strace

或类似的东西:

sudo strace -fp PID

另一个hacky技巧可能是执行命令,然后在附加到进程后立即执行。以下是一些例子:

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只是在第一次运行时缓存密码,

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

  • 您必须在两个地方输入命令,

  • 您可以忽略&将流程运行到后台,如果它已经这样做了,

  • 完成调试后,您必须手动终止后台进程(例如killall -v tail

答案 1 :(得分:8)

-n的{​​{1}}参数将导致dtruss等待并检查与dtruss的参数匹配的进程。 -n选项仍然可以跟踪从-f匹配的进程分叉的进程。

所有这些意味着如果你想要一个进程(为了争论,让我们说它是-n)作为非特权用户运行,请按照以下步骤操作:

  1. 打开root shell
  2. 运行whoami
    • 这将等待名为“whoami”的进程存在
  3. 打开非特权外壳
  4. 运行dtruss -fn whoami
    • 这将执行并正常退出
  5. 在dtruss窗口中观察系统调用跟踪
    • dtruss不会自行退出 - 它会继续等待匹配的进程 - 所以当你完成时就把它打破

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

答案 2 :(得分:5)

我不知道你是否可以像strace一样无所畏惧。

“sudo [to root] dtruss sudo [back to nonroot] cmd”的一个变体似乎在我的一些快速测试中效果更好:

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

外部sudo当然是以root身份运行。

内部su回到我身边,使用-l它可以正确地重新创建环境,此时我们需要回到我们开始的地方。

如果您希望环境成为用户通常获得的环境,我认为“su -l user”优于“sudo -u user”。那将是他们的登录环境;我不知道是否有一种让环境通过两个用户更改继承的好方法。

在你的问题中,除了丑陋之外,你还有一个关于“sudo dtruss sudo”解决方法的另一个抱怨是“我现在没有得到任何a.out文件,不知道为什么”。我不知道为什么,但在我的小测试脚本中,“sudo dtruss sudo”变体也无法写入测试输出文件,上面的“sudo dtruss su”变体确实创建了输出文件。

答案 3 :(得分:5)

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

答案 4 :(得分:3)

似乎OS X不支持使用dtrace复制所需的strace的所有功能。但是,我建议尝试围绕合适的系统调用创建一个包装器。看起来DYLD_INSERT_LIBRARIES是您想要破解的环境变量。这与Linux的LD_PRELOAD基本相同。

  

更容易实现库函数覆盖的方法是使用   DYLD_INSERT_LIBRARIES环境变量(类似于LD_PRELOAD on   Linux的)。概念很简单:在加载时动态链接器(dyld)   将加载DYLD_INSERT_LIBRARIES中指定的任何动态库   在可执行文件要加载的任何库之前。通过命名一个函数   与库函数中的一个相同,它将覆盖任何调用   原来。

     

原始函数也被加载,可以使用   dlsym(RTLD_NEXT,“function_name”);功能。这允许简单   包装现有库函数的方法。

根据exampleTom Robinson,您可能还需要设置DYLD_FORCE_FLAT_NAMESPACE=1

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

#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

答案 5 :(得分:2)

免责声明:这是来自@ kenorb&#39; s answer。它有一些优点: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的密码提示。

我们开始后台流程(&#34;等待1秒,然后做一些有趣的事情&#34;)。同时,我们启动DTrace。我们已将后台进程的PID捕获到$!,因此我们可以将其作为arg传递给DTrace。

关闭DTrace后kill $!运行。对于我们的cat示例(进程自行关闭),它不是必需的,但它可以帮助我们结束长期运行的后台进程,例如ping。将-p $!传递给DTrace是执行此操作的首选方法,但在macOS上显然需要代码签名的可执行文件。

你可以做的另一件事是在一个单独的shell中运行命令,然后窥探那个shell。查看我的answer

答案 6 :(得分:1)

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

但是,我相信你要找的命令而不是

dtruss -f sudo -u myusername gcc hello.c

sudo dtruss -f gcc hello.c

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

抱歉,我无法提供进一步的帮助。