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

发布于 2024-09-04 13:04:28 字数 983 浏览 9 评论 0 原文

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

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

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

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

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

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

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

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

I want to port memoize on the mac, so I need some kind of strace. What I actually need is the list of files gcc reads and writes into, so what I need is more of a truss. Sure enough can I say dtruss -f gcc hello.c and 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.out file is now owned by 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.out file at all this time, not sure why)

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

抱着落日 2024-09-11 13:04:28

最简单的方法是使用 sudo:

sudo dtruss -f sudo -u $USER whoami

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

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

The easiest way is to use 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


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

sudo dtruss -fp PID

or similar on Linux/Unix by using 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, date as 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)

萌无敌 2024-09-11 13:04:28

dtruss-n 参数将导致 dtruss 等待并检查与 -n 参数匹配的进程。 -f 选项仍然可以跟踪从 -n 匹配的进程派生的进程。

所有这些意味着,如果您想 dtruss 一个以非特权用户身份运行的进程(为了方便讨论,假设它是 whoami),请按照以下步骤操作:

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

这个答案重复了 @kenorb 响应的后半部分,但它值得成为一流的回答。

The -n argument to dtruss will cause dtruss to wait and examine processes that match the argument to -n. The -f option will still work to follow processes forked from the processes matched by -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:

  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

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

飞烟轻若梦 2024-09-11 13:04:28

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

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 in the 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!

画▽骨i 2024-09-11 13:04:28

我不知道你是否能让 dtruss 变得像 strace 一样无创。

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

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

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

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

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

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

I don't know if you can get dtruss to be as noninvasive as 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 dtruss -f su -l `whoami` cd `pwd` && cmd....

The outer sudo is of course so dtruss runs as 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.

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.

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.

变身佩奇 2024-09-11 13:04:28

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

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

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

根据 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

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_LIBRARIES is the environment variable you want to hack a bit. That's basically the same as LD_PRELOAD for Linux.

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.

According to the example by Tom Robinson you may need to set DYLD_FORCE_FLAT_NAMESPACE=1, too.

Copy of the original example (lib_overrides.c) that overrides only 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
绿光 2024-09-11 13:04:28

免责声明:这源自@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 捕获到 $! 中,因此我们可以将其作为参数传递给 DTrace。

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


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

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.

This is a bit race-conditiony, but…

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

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

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

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.

The kill $! runs after we close DTrace. It's not necessary for our cat example (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.


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

不必了 2024-09-11 13:04:28

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

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

dtruss -f sudo -u myusername gcc hello.c

sudo dtruss -f gcc hello.c

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

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

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.

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

dtruss -f sudo -u myusername gcc hello.c

is

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.

Sorry I couldn't be of further help.

爱已欠费 2024-09-11 13:04:28

由于缺乏声誉,我无法对 kenorb 的回答发表评论。但只是想添加 -W 选项将导致 dtruss 等待指定进程启动,以便输出不包含大量不相关的系统调用。所以

sudo dtruss -fW whoami

让我找到了我的问题,因为事情被使用 -fn 选项埋葬了。

I am unable to comment on kenorb's answer due to lack of reputation. But just wanted to add that the -W option will cause dtruss to wait for the named process to start, so that the output doesn't contain lots of unrelated system calls. So

sudo dtruss -fW whoami

allowed me to find my issue, where as things were buried using the -fn options.

明天过后 2024-09-11 13:04:28

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

$ sudo dtruss -fn Preview 2>&1 |

输入密码后,我启动了 Preview,当 dtruss 打印

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

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

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

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

如果这是系统范围的问题,您可能更喜欢 grep '"/'
但这会在 /usr/System 等地方向您发送数百个无辜的项目。

从 MacOSX 11.6 “El Capitan” dtrace/dtruss 开始,默认情况下,dtrace/dtruss 已被禁用 - 请参阅如何 修复它

我使用这个 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 "$0" "$@"' "$@"
        ;;
    esac
}

很久以前,我们使用 Apple 计算机来推送数据,使用 Levi's 牛仔裤来驱动拖拉机 - 两者都已退化为单纯的时装公司。 SF distopia 白痴似乎是相关的。

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

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

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

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~)

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, /System and so on.

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

I use this bash function, e.g., $ 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 "$0" "$@"' "$@"
        ;;
    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 Idiocracy seems relevant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文