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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3007868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 06:59:43  来源:igfitidea点击:

How can I get dtrace to run the traced command with non-root priviledges?

macosrootdtracestrace

提问by Gyom

OS X lacks linux's strace, but it has dtracewhich is supposed to be so much better.

OS X缺乏的linux的strace,但它有dtrace它应该是好多了。

However, I miss the ability to do simple tracing on individual commands. For example, on linux I can write strace -f gcc hello.cto caputre all system calls, which gives me the list of allthe filenames needed by the compiler to compile my program (the excellent memoizescript is built upon this trick)

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

I want to port memoize on the mac, so I need some kind of strace. What I actually need is the list of files gccreads and writes into, so what I need is more of a truss. Sure enough can I say dtruss -f gcc hello.cand get somewhat the same functionality, but then the compiler is run with root priviledges, which is obviously undesirable (apart from the massive security risk, one issue is that the a.outfile is now owned by root :-)

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

I then tried dtruss -f sudo -u myusername gcc hello.c, but this feels a bit wrong, and does not work anyway (I get no a.outfile at all this time, not sure why)

然后我尝试了dtruss -f sudo -u myusername gcc hello.c,但这感觉有点不对,无论如何都不起作用(我一直没有a.out文件,不知道为什么)

All that long story tries to motivate my original question: how do I get dtraceto run my command with normal user privileges, just like stracedoes in linux ?

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

Edit: is seems that I'm not the only one wondering how to do this: question #1204256is pretty much the same as mine (and has the same suboptimal sudo answer :-)

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

采纳答案by netcharmer

Not an answer to your question but something to know. OpenSolaris solved this issue (partially) with "privileges" - see this page. Even in OpenSolaris, it wouldn't be possible to allow an user, without any extra privileges, to dtruss their own process. The reason is the way dtrace works - it enables probes inthe kernel. So allowing a non-privileged user to probe kernel means the user can do lot of unwanted things e.g. sniffing other user's passwd by enabling probes in keyboard driver!

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

回答by kenorb

The easiest way is to use sudo:

最简单的方法是使用 sudo:

sudo dtruss -f sudo -u $USER whoami


Other solution would be to run the debugger first and monitor for new specific processes. E.g.

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

sudo dtruss -fn whoami

Then in another Terminal simply run:

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

whoami

Simple as that.

就那么简单。

More tricky arguments you can find in the manual: man dtruss

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



Alternatively you can attach dtruss to the running user process e.g. on Mac:

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

sudo dtruss -fp PID

or similar on Linux/Unix by using strace:

或在 Linux/Unix 上使用 strace 进行类似操作:

sudo strace -fp PID


Another hacky trick could be to execute the command and right after that attach to the process. Here are some examples:

另一个技巧可能是执行命令,然后立即附加到进程。这里有些例子:

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`

Note:

笔记:

  • first sudo is just for caching the password at the first time of running,

  • this trick doesn't work for quick command lines like ls, dateas it takes some time untill debugger will attach to the process,

  • you have to type your command in two places,

  • you can ignore &to run the process to the background, if it's already doing that,

  • after finishing debugging, you'll have to manually kill the background process (e.g. killall -v tail)

  • 第一个 sudo 只是为了在第一次运行时缓存密码,

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

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

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

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

回答by wfaulk

The -nargument to dtrusswill cause dtruss to wait and examine processes that match the argument to -n. The -foption will still work to follow processes forked from the processes matched by -n.

-n参数dtruss将导致dtruss等待和检查相匹配的参数传递给进程-n。该-f选项仍然可以跟踪从匹配的进程派生出来的进程-n

All this means that if you want to dtruss a process (for the sake of argument, let's say it's whoami) running as your nonprivileged user, follow these steps:

所有这一切意味着,如果您想以非whoami特权用户身份运行一个进程(为了争论,假设它是),请执行以下步骤:

  1. Open a root shell
  2. Run dtruss -fn whoami
    • this will sit and wait for a process named "whoami" to exist
  3. Open a nonprivileged shell
  4. Run whoami
    • this will execute and exit normally
  5. Observe system call trace in dtruss window
    • dtruss will not exit on its own — it will continue waiting for matching processes — so break out of it when you're done
  1. 打开一个根外壳
  2. dtruss -fn whoami
    • 这将等待一个名为“whoami”的进程存在
  3. 打开非特权外壳
  4. whoami
    • 这将正常执行并退出
  5. 在 dtruss 窗口中观察系统调用跟踪
    • dtruss 不会自行退出——它会继续等待匹配的进程——所以当你完成后退出它


This answer duplicates the latter part of @kenorb's response, but it deserves to be a first-class answer.

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

回答by metamatt

I don't know if you can get dtruss to be as noninvasive as strace.

我不知道你是否可以让 dtruss 像 strace 一样无创。

A variant of the "sudo [to root] dtruss sudo [back to nonroot] cmd" that seems to work better in some quick testing for me is:

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

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

The outer sudo is of course so dtruss runs as root.

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

The inner su is back to me, and with -l it recreates the environment properly, at which point we need to cd back to where we started.

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

I think "su -l user" is better than "sudo -u user" if you want the environment to be what that user normally gets. That'll be their login environment though; I don't know if there's a good way to let the environment inherit through the two user changes instead.

如果您希望环境成为用户通常获得的环境,我认为“su -l user”比“sudo -u user”更好。不过,那将是他们的登录环境;不知道有没有什么好办法让环境通过两次用户更改来继承。

In your question, one additional complaint that you had about the "sudo dtruss sudo" workaround, other than ugliness, was that "I get no a.out file at all this time, not sure why". I don't know why either, but in my little test script, a "sudo dtruss sudo" variant also failed to write to a test output file, and the "sudo dtruss su" variant above did create the output file.

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

回答by Mikko Rantalainen

It seems that OS X does not support using dtrace to replicate all the features of strace that you need. However, I'd suggest trying to create a wrapper around suitable syscalls. It looks like DYLD_INSERT_LIBRARIESis the environment variable you want to hack a bit. That's basically the same as LD_PRELOADfor Linux.

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

A much easier way of doing library function overrides is using the DYLD_INSERT_LIBRARIES environment variable (analogous to LD_PRELOAD on Linux). The concept is simple: at load time the dynamic linker (dyld) will load any dynamic libraries specified in DYLD_INSERT_LIBRARIES before any libraries the executable wants loaded. By naming a function the same as one in a library function it will override any calls to the original.

The original function is also loaded, and can be retrieved using the dlsym(RTLD_NEXT, “function_name”); function. This allows a simple method of wrapping existing library functions.

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

原始函数也被加载,可以使用 dlsym(RTLD_NEXT, “function_name”); 检索;功能。这提供了一种包装现有库函数的简单方法。

According to the exampleby Tom Robinsonyou may need to set DYLD_FORCE_FLAT_NAMESPACE=1, too.

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

Copy of the original example (lib_overrides.c) that overrides only fopen:

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;
}

Usage:

用法:

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

回答by Birchlabs

Disclaimer: this is derived from @kenorb's answer. It has some advantages though: PID is more specific than execname. And we can make a short-lived process wait for DTrace before it begins.

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

This is a bit race-conditiony, but…

这有点竞争条件,但是......

Let's say we want to trace cat /etc/hosts:

假设我们要跟踪cat /etc/hosts

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

We use sudo trueto make sure that we clear sudo's password prompt before we start running anything time-sensitive.

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

We start a background process ("wait 1 sec, then do something interesting"). Meanwhile, we start DTrace. We've captured the background process's PID into $!, so we can pass that to DTrace as an arg.

我们启动一个后台进程(“等待 1 秒,然后做一些有趣的事情”)。同时,我们启动DTrace。我们已将后台进程的 PID 捕获到 中$!,因此我们可以将其作为参数传递给 DTrace。

The kill $!runs after we close DTrace. It's not necessary for our catexample (process closes on its own), but it helps us end long-running background processes like ping. Passing -p $!to DTrace is the preferred way to do this, but on macOS apparently requires a code-signed executable.

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



The other thing you can do is to run the command in a separate shell, and snoop that shell. See my answer.

您可以做的另一件事是在单独的 shell 中运行命令,并监听该 shell。看我的回答

回答by aqua

I don't know of a way to run what you want as a normal user, as it seems that dtruss, which uses dtrace requires su privileges.

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

However, I believe the command you were looking for instead of

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

dtruss -f sudo -u myusername gcc hello.c

dtruss -f sudo -u myusername gcc hello.c

is

sudo dtruss -f gcc hello.c

sudo dtruss -f gcc hello.c

After typing in your password, dtruss will run dtrace will sudo privileges, and you will get the trace as well as the a.out file.

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

Sorry I couldn't be of further help.

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

回答by devon

I fixed my broken Preview with this general method to diagnose and fix crashing appsin Terminal.app at a bash prompt:

我使用这种通用方法修复了损坏的预览,在 bash 提示符下诊断和修复Terminal.app 中的崩溃应用程序

$ sudo dtruss -fn Preview 2>&1 | grep '/Users/'

$ sudo dtruss -fn Preview 2>&1 | grep '/Users/'

After entering my password, I launched Preview which promptly crashed while dtruss printed

输入密码后,我启动了预览,但在打印 dtruss 时它立即崩溃了

70256/0x19cd898: chdir("/Users/devon/Library/Containers/com.apple.Preview/Data\0", 0x0, 0x7FFF5EAC4BC8) = 0 0

70256/0x19cd898: chdir("/Users/devon/Library/Containers/com.apple.Preview/Data\0", 0x0, 0x7FFF5EAC4BC8) = 0 0

rather than delete this likely suspect, I renamed it

我没有删除这个可能的嫌疑人,而是将其重命名

$ (cd ~/Library/Containers && mv -i com.apple.Preview com.apple.Preview.~NOT~)

$ (cd ~/Library/Containers && mv -i com.apple.Preview com.apple.Preview.~NOT~)

Preview now works normally and has created a new, non-toxic version of the directory I got rid of.

预览现在可以正常工作,并为我删除的目录创建了一个新的、无毒的版本。

You might prefer grep '"/'in case it's a system-wide problem but that spams you with hundreds of innocent items in /usr, /Systemand so on.

grep '"/'如果这是一个系统范围的问题,但它会向您发送数百个无害项目的垃圾邮件,您可能更愿意/usr/System依此类推。

As of MacOSX 11.6 "El Capitan" dtrace/dtruss is crippled by default — see how to fix it.

从 MacOSX 11.6“El Capitan”dtrace/dtruss 开始,默认情况下是残缺的——看看如何修复它

I use this bash function, e.g., $ d /Applications/Preview.app/Contents/MacOS/Preview

我使用这个 bash 函数,例如,$ d /Applications/Preview.app/Contents/MacOS/Preview

d () 
{ 
    case "$*" in 
        [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9] | [0-9][0-9][0-9][0-9][0-9])
            dtruss -f -p "$*"
        ;;
        *)
            bash -c 'echo -en "\t <<< press return in this window to run after launching trace in root window like this >>> \t # d $$" >/dev/tty; (read -u3 3</dev/tty); exec "##代码##" "$@"' "$@"
        ;;
    esac
}

Aeons ago we used Apple computers to push data and Levi's jeans to drive tractors — both have devolved into mere fashion companies. The S-F distopia Idiocracyseems relevant.

很久以前,我们用苹果电脑来推送数据,用 Levi's 牛仔裤来驱动拖拉机——两者都已经沦为纯粹的时尚公司。SF distopia Idiocracy似乎相关。